【基础算法】位运算-找出奇特的数
来源:互联网 发布:postfix ubuntu 编辑:程序博客网 时间:2024/06/11 04:51
Leetcode 里面有两道关于找出落单的数的题: single number 和 single number II
single number 这道题是让找出一个数组里唯一一个落单的数,其余的数都出现了2次
这道题首要想到的是异或,因为异或的性质中有A^A=0 0^A=A,这样就能找出那个只出现的1次的数,其余出现了2次的因为异或操作全部清零。
public int singleNumber(int[] A) { int result=0; for(int i=0; i<A.length; i++) { result=result^A[i]; } return result; }
如果我们扩展到只有一个数出现了2k+1次,其他数都出现了2k次,这道题同样能够求解。2k次的数全部清零,2k+1次的前2k次也全部清零,这样就剩下那个你要找的数了。
异或的思路局限性非常大,因此当出现single number 2这样的题的时候,采用异或将无从下手。
single number 2这道题是让找出一个数组里唯一一个落单的数,其余的数出现了3次。我们会发现,异或只对偶数次的数有清零作用,奇数次的数将没有太多办法。
所以Code_Ganker大神提出一个方法是将每个数的二进制位存起来,即构建一个32size的数组用于存放所有的Integer。数组的每一个数向右移动i次再与上1(i=0 to 31)这样每个数的第i位就存在了这个32size的数组里(i=0 to 31)。
int[] digit = new int[32]; for(int i=0; i<32; i++) { for(int j=0; j<A.length; j++) { digit[i]+=(A[j]>>i)&1; } }
这样,每个digit数组的元素要么是0,要么一定是3k或者3k+1,我们假设没有那个落单的数,这个时候数组的每个元素除了0,一定是3k,所以唯一造成3k+1的数就是那个落单的数,找出即可,因此只需要模上3,就可以找出那个落单的数。
for(int i=0; i<32; i++) result|=(digit[i]%3)<<i;
附上single number II 的完整代码 (作者是Code_Ganker)
public static int singleNumber(int[] A) {int result=0;int[] digit = new int[32];for(int i=0; i<32; i++) {for(int j=0; j<A.length; j++) {digit[i]+=(A[j]>>i)&1;}}for(int i=0; i<32; i++) {result|=(digit[i]%3)<<i;}return result;}
如果我们继续扩展,扩展成其他数出现了m次就一个出现了1次呢,这样数组的元素为mk或者mk+1。只需要模上m就可以了。
如果我们再继续扩展,扩展成其他数出现了m次,就一个出现了n次呢,这样数组的元素位mk或者mk+n。
如果m>n, 模上m后,mk%m=0, (mk+n)%m=n,这样可以通过发现不等于0的位来找出那个出现n次的数。这时候用1<<i代替(digit[i]%m)<<i即可。
如果m<n, 模上m后,mk%m=0, (mk+n)%m=? 未知!我们继续讨论
如果n是m的倍数,这样模上m后会全部被清0,所以不能用这样的方法。
如果n不是m的倍数,这样模上m后,n会出现剩余,此时可以用这种方法。
附上这种思想的代码
for (int i = 0; i < 32; i++) {if (digit[i] % 3 != 0)result |= 1 << i;}return result;
- 【基础算法】位运算-找出奇特的数
- 位运算数的运算
- 【基础算法】位运算-基本运算
- 找出21位的水仙数
- 【基础算法】位运算-基础篇
- __15__C#基础的位运算
- JavaScript中奇特的~运算符
- 位运算的一些算法
- 关于位运算的算法
- 【基础算法】排序-复杂排序之二(找出第K大的数)
- 程序员面试100题(算法)之找出数组中两个只出现一次的数字(位运算实现)
- 十分奇特的规则数独
- 3个奇特的数独
- 位运算---不用任何比较判断找出两个数中的最大值
- 位运算求解两个数的平均值
- 位运算求解两个数的平均值
- 位运算求两个数的平均值
- 位运算实现两个数的加法
- Java中Vector、LinkedList和ArrayList的区别
- JAVA中HashMap和Hashtable区别
- RELIEF Feature Selection(RELIEF特征选择) Python实现
- java中int和string类型转换
- Java关键字final、static使用总结
- 【基础算法】位运算-找出奇特的数
- [Leetcode] Divide Two Integers
- Java基本概念:集合类(Collection)List/Set/Map... 的区别和联系
- 网上无法找到的教程,LZMA教程,欢迎大家指正
- lu 初始化设置步骤
- 发了个快递是法国
- Java程序员的JavaScript学习笔记(5——prototype和Object内置方法)
- [Leetcode] Search in Rotated Sorted Array
- PHP中的定界符 EOT