异或运算算法相关
2016-12-07 17:41
239 查看
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字?”这是经典的算法题,乍看这个题的思路特别多。
这道题的实现方法很多,关键是找到最好的实现方法很难,本文就介绍采用异或运算实现这道题目的解法。
异或运算是C语言中位运算的一种操作,这种操作对于嵌入式程序员可能比较熟悉,但是对于一般的程序员可能运用的比较少,异或操作具有如下的特征:
0^num = num; 1^num = ~num; num ^ num = 0; 其中num = 0或者1。
a^a^b^b^c = (a^a)^(b^b)^c=0^0^c=c;
需要注意:如果有a + b = c; 则有可能使得a ^ b ^ c = 0;这个条件是非充分非必要,比如a = 1,b = 2, c = 3,这时候的a ^ b ^ c = 0是成立的,但是a = 2, b = 2, c = 4,则是不成立的。
假设数组元素为a
,其中N的值很大,不成对的元素为an,am。实现上述过程的步骤如下所示:
首先,变量元素对所有元素进行异或操作,得到的结果肯定是an^am。也就说通过异或操作以后,结果中保存了an和am的特征。由于am和an不同,am^an的结果肯定是大于等于1。am和an不同,那么am^an中为1的某一个bit肯定是am或者an中某一个的特征。
然后,定义两个值num1,num2,分别用来计算an、am,选择am^an中的某一个bit作为特征位。
假设是第K位是特征位,再次对元素进行遍历:
如果元素的第K位是1,这个元素可能是am或者an,那么将当前元素与num1进行异或操作;
如果元素的第K位为0,那么这个元素则可能是另一个值,那么将当前元素与num2进行异或操作。
这样遍历完所有元素,因为大部分数据成对出现,根据异或运算的特征,num1,num2就分别保存了两个不同的值,这两个值即为我们所求。
由上面的分析可知,这种算法只需要遍历两次数组空间即可实现数据的判定,这样时间复杂度为O(N),同时因为没有hashmap之类的结构体,这样空间复杂度就是O(1)。这种算法的实现肯定是最佳的。相比前面提到的hashmap、排序算法时间复杂度和空间复杂度都要小,因此这种算法的实现应该是最佳的。
例如:1 2 3 4 7 3 2 1 4 9
异或和即7^9=1110,取倒数第二位为特征位;
对于2 3 7 3 2 它们的倒数第二位都为1,异或和为7;
对于1 4 1 4 9 它们的倒数第二位都为0,异或和为9;
代码实现:
这道题的实现方法很多,关键是找到最好的实现方法很难,本文就介绍采用异或运算实现这道题目的解法。
异或运算是C语言中位运算的一种操作,这种操作对于嵌入式程序员可能比较熟悉,但是对于一般的程序员可能运用的比较少,异或操作具有如下的特征:
0^num = num; 1^num = ~num; num ^ num = 0; 其中num = 0或者1。
a^a^b^b^c = (a^a)^(b^b)^c=0^0^c=c;
需要注意:如果有a + b = c; 则有可能使得a ^ b ^ c = 0;这个条件是非充分非必要,比如a = 1,b = 2, c = 3,这时候的a ^ b ^ c = 0是成立的,但是a = 2, b = 2, c = 4,则是不成立的。
假设数组元素为a
,其中N的值很大,不成对的元素为an,am。实现上述过程的步骤如下所示:
首先,变量元素对所有元素进行异或操作,得到的结果肯定是an^am。也就说通过异或操作以后,结果中保存了an和am的特征。由于am和an不同,am^an的结果肯定是大于等于1。am和an不同,那么am^an中为1的某一个bit肯定是am或者an中某一个的特征。
然后,定义两个值num1,num2,分别用来计算an、am,选择am^an中的某一个bit作为特征位。
假设是第K位是特征位,再次对元素进行遍历:
如果元素的第K位是1,这个元素可能是am或者an,那么将当前元素与num1进行异或操作;
如果元素的第K位为0,那么这个元素则可能是另一个值,那么将当前元素与num2进行异或操作。
这样遍历完所有元素,因为大部分数据成对出现,根据异或运算的特征,num1,num2就分别保存了两个不同的值,这两个值即为我们所求。
由上面的分析可知,这种算法只需要遍历两次数组空间即可实现数据的判定,这样时间复杂度为O(N),同时因为没有hashmap之类的结构体,这样空间复杂度就是O(1)。这种算法的实现肯定是最佳的。相比前面提到的hashmap、排序算法时间复杂度和空间复杂度都要小,因此这种算法的实现应该是最佳的。
例如:1 2 3 4 7 3 2 1 4 9
异或和即7^9=1110,取倒数第二位为特征位;
对于2 3 7 3 2 它们的倒数第二位都为1,异或和为7;
对于1 4 1 4 9 它们的倒数第二位都为0,异或和为9;
代码实现:
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <set> #include <vector> using namespace std; const int N=1000005; int a ; int getBit(int n){//得到特征位 int i; for(i=1;;i++){ if(n&1){ return i; } else n=n>>1; } } int getBit2(int n,int i){//得到每个元素特征位的元素 int ans=0; for(int j=1;j<=i;j++){ ans=n&1; n=n>>1; } return ans; } int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } int ans=0; for(int i=1;i<=n;i++) { ans^=a[i]; } int ansbit=getBit(ans); int num1=0,num2=0; for(int i=1;i<=n;i++){ if(getBit2(a[i],ansbit)==1){ num1^=a[i]; } else num2^=a[i]; } printf("%d %d\n",min(num1,num2),max(num1,num2)); } return 0; } /* 3 10 1 2 3 4 7 3 2 1 4 9 6 2 2 1 1 3 4 4 1 1 3 4 */
相关文章推荐
- C++异或运算在算法中的经典运用
- [算法][LeetCode]Single Number——异或运算的巧妙运用
- 异或运算在算法中的经典运用
- 利用“异或”处理数组的相关算法的几个例子
- 异或运算在算法编程题中的应用
- “异或”处理数组的相关算法的面试题
- Java使用异或运算实现简单的加密解密算法实例代码
- [算法][LeetCode]Single Number——异或运算的巧妙运用
- 利用“异或”处理数组的相关算法的几个例子
- [置顶] 与位运算相关的编程算法技巧的总结java实现
- 落单的数算法(巧妙的异或运算)
- 异或运算的经典算法题:找出数组中只出现一次的数字,其它数字都出现了两次
- 实现广义表的相关运算算法(一)
- Java简单的加密解密算法,使用异或运算
- Java简单的加密解密算法,使用异或运算
- (译)算法之美(1)--书籍与运算法则
- 数据结构复习:几种排序算法的C++实现和二叉树的相关算法实现
- 异或运算、与运算、或运算在设计复选框中的应用
- 【项目】优化算法设计(一):《遗传算法与工程优化》相关部分内容
- 浅析CBIR中基于SVM的相关反馈算法