n重复数组,是指数组中的数字都出现n次;

唯一m重复异类数,是指存在唯一一个没出现n次,只出现了m次的数;

这里我简记它为nX+my问题,求解y,其中m < n,数组中都是整数;

3X+y问题

一直没有精力刷leetcode,今天查问题无意中看到了leetcode 137:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次;找出那个只出现了一次的元素。要求时间复杂度O(n),空间复杂度O(1);

没有在第一时间想到思路,于是花时间研究了一下;

这是一个3X+y的问题;先给出最优解:

        a, b = 0, 0for num in nums:a =  (a ^ num)  & ~bb =  (b ^ num)  & ~areturn a

在2X+y问题中,方法是使用异或操作一遍全数组,最终结果就是那个异类数,但从未深入想过为什么异或会对2X+y问题有效,因而也就无法想通为什么直接异或会对3X+y问题无效;

再看一遍异或的特点:

0 ^ 0 = 0
1 ^ 0 = 1
0 ^ 1 = 1
1 ^ 1 = 0

仔细看看,这是因为异或可以让一个信息位(前面的那个1bit数),在接收到有效信息量(后面的那个1bit数,值为1时为有效)的时候,产生二态变化;

因而如果要解决3X+y问题,就需要有一个可以产生三态变化的操作符,单纯的异或是肯定不行的,因为要对一个信息位保存三种状态,至少需要两个信息位,因而在原本的数字变量空间上操作是不够的;

假定这个三态异或操作用符号^3表示;然后用两个信息位(b, a)保存状态,于是三态异或在接收到有效信息量(1)时的运算特点如下(接收到无效信息量0时不产生变化):

(0, 0)  ^3  1 =  (0, 1)
(0, 1)  ^3  1 =  (1, 0)
(1, 0)  ^3  1 =  (0, 0)

这个三态变化过程,其实是正常的两位二进制数进位加法的一个修改,修改处在于,对于二进制10,再加1时,直接跳过11回到00;

因而这个状态变化过程可描述为:

  1. 两位二进制数的低位a,在高位b为0时,进行二态变化;在高位b为1时,归0;
  2. 两位二进制数的高位b,在低位a归0时,进行二态变化;在低位a变为1时,保持为0;

可见a与b的变化规律相似,都要求对方为0时自己进行二态变化,对方为1时自己为0,于是上面的最优解的计算过程就很容易写出来了:

        a = (a ^ num) & ~bb = (b ^ num) & ~a

3X+2y问题

等等,为什么是return a,而不是return b呢?

首先,上面这段代码里的a、b各是一个数字,它位的每个二进制位组合起来,保存了对整个数组^3操作过程中每个二进制位的状态变化;

因为这个^3操作过程中,低位a在第一状态有效,因而要求3X+y问题,需要return a;

因而,如果题目改为:给定一个非空整数数组,除了某个元素只出现两次以外,其余每个元素均出现了三次;找出那个只出现了两次的元素。

求解这个3X+2y问题,答案也就出来了,计算过程同上,而因为高位b在第二状态有效,因而return b即可;

4X+2y问题

再发散思维,改题目:给定一个非空整数数组,除了某个元素只出现两次以外,其余每个元素均出现了四次;找出那个只出现了两次的元素。

沿着上面的思路,需要做一个四态异或操作符^4,同样需要两个信息位进行状态存储,它对于有效信息(1)的运算特点如下:

(0, 0) ^4  1 = (0, 1)
(0, 1) ^4  1 = (1, 0)
(1, 0) ^4  1 = (1, 1)
(1, 1) ^4  1 = (0, 0)

这就是标准的两位二进制数加法,状态变化过程可描述为:

  1. 两位二进制数的低位a,正常进行二态变化;
  2. 两位二进制数的高位b,在低位a进位的时候进位二态变化;

于是计算过程可写为:

        old_a = aa = (a ^ num)b = b ^ ((old_a ^ a) & ~a)

其中(old_a ^ a) & ~a,意义为a由1变为0;

由于这个b的计算核心算子是异或,异或与否合用有危险,不把(old_a ^ a)引进来会出现bug;

因为要求的y出现2次,所以需要找第二状态时的有效位,return b;

4X+3y问题

状态数同时为4,计算过程同4X+2y,返回时找第三状态时的有效位,因而也return b;

5X+4y问题

题目修改为:给定一个非空整数数组,除了某个元素只出现4次以外,其余每个元素均出现了5次;找出那个只出现了4次的元素。

状态数上升到5,需要做一个五态异或操作符^5,需要3个信息位(c, b, a)做状态存储,对有效信息(1)的运算特点如下:

(0, 0, 0) ^5  1 = (0, 0, 1)
(0, 0, 1) ^5  1 = (0, 1, 0)
(0, 1, 0) ^5  1 = (0, 1, 1)
(0, 1, 1) ^5  1 = (1, 0, 0)
(1, 0, 0) ^5  1 = (0, 0, 0)

状态变化过程可描述为:

  1. 三位二进制数的低位a,在高位c为0时,进行二态变化;在高位c为1时,归0;
  2. 三位二进制数的中位b,在高位c为0时,低位a进位的时候进位二态变化;在高位c为1时,归0;
  3. 三位二进制数的高位c,在低位a和中位b同时归0时,进行二态变化;

计算过程可写为:

        old_a = aa = (a ^ num) & ~cb = (b ^ ((old_a ^ a) & ~a)) & ~cc = (c ^ num) & ~b & ~a

由于y出现的次数是4,高位c在状态4时有效,因而返回c;

-----------------------------

测试代码:

def X3_y1(nums):a, b = 0, 0for num in nums:a =  (a ^ num)  & ~bb =  (b ^ num)  & ~areturn adef X3_y2(nums):a, b = 0, 0for num in nums:a =  (a ^ num)  & ~bb =  (b ^ num)  & ~areturn bdef X4_y2(nums):a, b = 0, 0for num in nums:old_a = a a =  (a ^ num)b =  b ^ ((old_a ^ a) & ~a) return bdef X4_y3(nums):return X4_y2(nums)def X5_y4(nums):a, b, c = 0, 0, 0for num in nums:old_a = a a =  (a ^ num) & ~cb =  (b ^ ((old_a ^ a) & ~a)) & ~cc =  (c ^ num) & ~b & ~areturn cprint (X3_y1([2, 3, 2, 2]))  # 3
print (X3_y2([2, 3, 2, 3, 2]))   # 3print (X4_y2([2, 2, 3, 2, 3, 2]))   # 3
print (X4_y3([2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 2]))   #4
print (X4_y3([5, 5, 8, 5, 8, 8, 5]))   # 8print (X5_y4([5, 5, 8, 5, 8, 8, 5, 8, 5]))   # 8

执行结果:

3
3
3
4
8
8

转载于:https://www.cnblogs.com/ZisZ/p/10442182.html

[算法] 举一反三之n重复数组中找唯一m重复异类数相关推荐

  1. python查找数列中重复数字_在数组中找出重复的数字(异或法)

    购买本课程后,可以加51CTO学院李宁老师官方交流群:550369460注意,该群只允许购买李宁老师课程的学员进行技术交流,加群时需要提供在51CTO购买李宁老师课程的订单编号(任何一个课程的订单编号 ...

  2. 【回溯算法】【打卡第179道】:leetCode :39. 组合总和(数组中的元素可以重复使用)

    1.题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有不同组合 ,并以列表形式 ...

  3. 【算法】快速选择算法 ( 数组中找第 K 大元素 )

    算法 系列博客 [算法]刷题范围建议 和 代码规范 [算法]复杂度理论 ( 时间复杂度 ) [字符串]最长回文子串 ( 蛮力算法 ) [字符串]最长回文子串 ( 中心线枚举算法 ) [字符串]最长回文 ...

  4. 算法练习day19——190410(数组中重复的数字、替换空格、从尾到头打印链表)

    1.数组中重复的数字 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次.请找出数组中任意一个重复的数字. ...

  5. C语言数组中找到第一个重复元素的算法(附完整源码)

    C语言数组中找到第一个重复元素的算法 C语言数组中找到第一个重复元素的算法完整源码(定义,实现,main函数测试) C语言数组中找到第一个重复元素的算法完整源码(定义,实现,main函数测试) #in ...

  6. 数据结构与算法--有序数组中找出和为s的两个数字

    有序数组中找和为s的两个数字 题目:输入一个递增排序的数组array, 和一个数字s, 在数组中找出两个数,使得这两个数的和是s,如果有多对,输出一对即可. 最简单方案 双循环,每次获取一个数据,和数 ...

  7. 给出一个分治算法,在一个具有n个数的数组中找出第二个最大元素。给出你算法的时间复杂性

    给出一个分治算法,在一个具有n个数的数组中找出第二个最大元素.给出你算法的时间复杂性. 算法 SECOND_MAX 输入:含有n个元素的数组A,不妨设 n=2^k 输出:该数组中的第二个最大元素 ( ...

  8. 【宫水三叶的刷题日记】961. 在长度 2N 的数组中找出重复 N 次的元素

    题目描述 这是 LeetCode 上的 961. 在长度 2N 的数组中找出重复 N 次的元素 ,难度为 简单. Tag : 「模拟」.「计数」.「构造」.「哈希表」 给你一个整数数组 nums ,该 ...

  9. 编写一个程序,从10亿个数字的数组中找出100个最大的数字

    本文翻译自:Write a program to find 100 largest numbers out of an array of 1 billion numbers I recently at ...

最新文章

  1. html调用百度地图语音播报,实现百度地图导航演示的语音播放功能
  2. 传统企业向产业互联网转型的两条路径
  3. 阿里云OSS上传文件demo
  4. 7-2 jmu-Java-01入门-取数字 (2 分)
  5. java 路径 20,java中得到classpath和当前类的绝对路径的一些方法(路径中的%20进行替换空格)...
  6. 帆软报表(finereport) 饼图联动
  7. 华为服务器清除系统日志,清空服务器日志
  8. linux 创建LVM磁盘
  9. Tensorflow——构造神经网络
  10. vim 使用、设置笔记
  11. 【图像融合】基于matlab curvelet变换图像融合【含Matlab源码 776期】
  12. Markdown latex语法合集
  13. java文字竖排_Java输出竖排文字
  14. 问卷设计中 你经常使用计算机吗,计算机应用基础课程调查问卷
  15. 【每日随笔】操控人性 ① ( 圣人的治理原则 | 控制人性的三大手段 - 引导 / 转移注意力 / 打击异己 | 作出正确的引导 | 不尚贤,使民不争 | 不追求权利 / 财富 )
  16. 测绘资质办理需要注意的流程和规定
  17. R plot图片背景设置为透明_R语言数据可视化基因名称转换及KEGG/GO富集分析
  18. 【超级视客营】基于超算平台的MMYOLO实践过程记录(自定义数据集实现YOLO v5)
  19. 四川金弘同创:拼多多推广方式在哪里设置
  20. facebook使用教程_您可以在Facebook上使用假名吗?

热门文章

  1. 虚拟化笔记05 OpenFiler configuration
  2. android构建过程
  3. es6学习笔记-字符串的扩展_v1.0_byKL
  4. 【Other】Ubuntu 14.04 pptp 客户端连接配置
  5. iOS 富文本类库RTLabel
  6. JavaScript对象的创建之动态原型方式
  7. 《自己动手写开发工具》试读版电子书及光盘
  8. how to add one row in the dataframe?
  9. UNITY 带spriterender的对象导出为prefab时主贴图丢失的BUG
  10. iOS Sharing #02 | 2019-03-30