位运算解决“一个数组中,只有一个数字出现n次,其他数字出现k次”问题
来源:互联网 发布:淘宝卖家创业故事 编辑:程序博客网 时间:2024/05/22 16:56
在学习完位操作后,经常会遇到一类关于查找缺失整数的问题。
第一类是给你一个数组,告诉你这些数字的范围是什么,然后让你查找这个缺失的数字(例如无序数组的范围是从1到10,不重复的9个数)。
这类问题的解决方法比较多样,第一种,因为给定了范围可以通过计算数字总和值,然后分别减去这些数字,剩下的则是缺失的数字。第二种,对这个数组进行排序,遍历整个数组,然后判断相邻的元素是否连续,如果是,那缺失的数字则在两段;如果不连续,中间缺少的则是需要查找的。
第二类还是给你一个数组,然后这些数字都出现了偶数次,只有一个数字出现了奇数次,让你查找这个奇数次的数字,例如( 1, 2, 3, 4, 1, 2, 3)。
思路:通过一种运算,让相同的元素在进行运算后可以相互消除,最后剩下的元素则是寻找的元素。这种位运算就是“异或”。通过异或,相同的数所有位都是0,而单独的那个数则是它本身。
#include<stdio.h>int single_numble(int arr[],int size){ int i = 0; int sum = 0; for (i = 0; i < size; i++) { sum ^= arr[i]; } return sum;}int main(){ int arr[] = { 1, 2, 3, 4, 1, 2, 3 }; int ret = single_numble(arr, sizeof(arr) / sizeof(arr[0])); printf("%d\n", ret); system("pause");}
当题目条件发生改变,这个数组的数字可能出现了多次,但还是只有一个数字出现了一次,查找这个数字(假设在这里是出现了3次)。
思路:对于整数32位,对于每一位,整个数组的数加起来去除3的余数,就是在该元素在此位上的值。
#include<stdio.h>int single_numble(int arr[],int size){ int i = 0; int j = 0; int ret = 0; int val = 0; for (i = 0; i < 32; i++) { int count = 0; //计数器 int mask = 1 << i; //mask的第i位为1,其余的位为0 for (j = 0; j < size; j++) { val = arr[j] & mask; if ((val>0) || (val < 0)) //如果该数在j位上为1,计数一次 count++; } if (count % 3>0) //这一位的计数除以3取余,在这里只能为1/0 ret|= mask; } return ret;}int main(){ int arr[] = {2,2,2,4}; int ret = single_numble(arr, sizeof(arr) / sizeof(arr[0])); printf("%d\n", ret); system("pause");}
总结:当一个数组有一个数恰好出现了k次,都可以用这个方法来解决。利用合适的位运算符将每一位保存,然后在找出这一位原来的数字。
第三类将难度又提升了,还是给你一个数组,里面的数字还是成对出现的,但单独出现的数字变成了两个,查找这两个数字。
思路:还是可以运用位运算的,将这个数组分成两部分,每一部分包含一个只出现一次的整数,这样子题目就和第二类差不多了。具体步骤是先对数组的每一个元素进行异或,得到的是两个数异或的结果,在这个结果中至少包含一个二进制位是1。
#include<stdio.h>int research(int arr[],int len,int *p1,int *p2){ int i = 0; int res = 0; int pos = 0; for (i = 0; i < len; i++) //对所有的元素进行异或 { res ^= arr[i]; } for (i = 0; i < len; i++) //找出一个二进制位为1的位置 { if ((res << i) & 1 == 1) { pos = i; break; } } for (i = 0; i < len; i++) { if ((arr[i] >> pos) & 1 == 1) { (*p1) ^= arr[i]; } } (*p2) = res ^ (*p1);}int main(){ int arr[] = { 1, 3, 5, 7, 1, 3, 5, 8 }; int ret1 = 0; int ret2 = 0; research(arr, sizeof(arr)/sizeof(arr[0]), &ret1,&ret2); printf("这两个数字是:%d %d\n", ret1, ret2); system("pause");}
总结:任意选择一个二进制位,然后将数组分成两部分,其中一部分的末位是1,另一部分是0。由于这两个单独的数末位肯定不一样,所以分组后肯定不会在同一个组内。这个问题的解决思路就和上面比较相似了。
从上面的几个例子可以看出,查找缺失的数字主要是通过位运算符来抵消满足条件的元素,而将那些缺失的元素进行保存,最后在将缺失的元素输出到屏幕上。
- 位运算解决“一个数组中,只有一个数字出现n次,其他数字出现k次”问题
- 有一个数组,某些数字出现了N次,只有一个出现了M次,求出该数字
- C++算法之 一个数字只出现一次,其他数字出现3次or N次
- 一个整数数组,每个数字都出现K次,只有一个数字出现M次,找出这个数字(线性时间)
- 面试题:元素为32位整数的数组中只有一个数字出现2次,其余都是出现3次,求这个数
- [每日练习]一个数组中有一个数字只出现一次,其他数字都出现了偶数次。请找出一个只出现一次的数字
- 一道位运算的题目,一串数字,别的都出现了3次只有一个出现2次,要你找到他
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次
- 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
- 现在有N个数字,其中只有一个数字出现的次数是奇数次,如何找到这个数字?
- 【C语言】一组数据中只有一个数字出现了一次。 其他所有数字都是成对出现的。请找出这个数字。(使用位运算)
- 一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的。请找出这个数字。(使用位运算)
- 一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的。请找出这个数字。(使用位运算)
- 一组数据中只有一个数字出现了一次。 其他所有数字都是成对出现的。请找出这个数字。(使用位运算)
- 一组数据中只有一个数字出现了一次。 其他所有数字都是成对出现的。请找出这个数字。(使用位运算)
- 一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的,找出这个数字(使用位运算)
- 洛谷 P1072 Hankson 的趣味题(暴力版)
- Spring学习笔记 —— AOP(面向切面编程) 之AspectJ
- **[Lintcode] Max Points on a Line
- 10.25
- oracle用户创建、授权和权限设置
- 位运算解决“一个数组中,只有一个数字出现n次,其他数字出现k次”问题
- 【备忘】2016最新独家老罗Android视频教程第二季 下载
- 第二讲 GC(垃圾回收)算法
- Boolean(翻译自mozilla developer network)
- 取消RadioButton前面小圆圈的方法
- java 之前的一些配置及简单运行
- JS——笔试点滴记录1——闭包与this及方法
- cacti--------(2)添加远程监控主机
- 动画闪屏页