异或(XOR)在算法中的一些适用情况
今天在做leetcode上的一道题时,发现了一种对异或操作的使用情况。
题目是这样子的:
Given an array of integers, every element appears twice except for one. Find that single one.
给你一个整型的数组,除了一个元素之外其余元素都只出现了两次,找到那一个独立的元素
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
算法要求时间复杂度是线性的,并且问你能否改进成不需要多余的内存。
这个题目本身如果没有算法要求是很简单的,如下:
1 int singleNumber(vector<int>& nums) { 2 for(vector<int>::iterator iter = nums.begin(); iter != nums.end(); ++iter){ 3 vector<int>::iterator pos = find(iter+1, nums.end(), *iter); 4 if(pos != nums.end()) 5 nums.erase(pos); 6 } 7 return nums[0]; 8 }
但是for循环遍历需要o(N)的复杂度,而find()也需要最少o(N)的复杂度,所以不满足题目对时间复杂度的要求。
这个时候百思不得其解,看看别人的答案,用到了 ^= ,思考了一下有不明白其中的原理,之前看CSAPP的时候学过XOR的操作,但是不明白为什么要用到这里。最后又搜了一下这个题目,终于明白其中的原委。
因为其他元素都出现了2次,因此根据XOR满足交换律的要求,可以知道其他所有元素(不包括那个只出现一次的元素)异或的结果是各个bit均为0的int,而一个变量各位均为0的话和其他变量进行XOR操作结果就是那个元素,这样就可以求出结果了。代码如下:
1 int singleNumber(vector<int>& nums) { 2 int result = 0; 3 if(nums.size() == 1) return nums[0]; 4 for(vector<int>::iterator iter = nums.begin(); iter != nums.end(); ++iter){ 5 result ^= *iter; 6 } 7 return result; 8 }
这个题目有一个升级版,就是在数组中有两个只出现一次的元素,让你求出,这里只给出一个思路:将数组拆分成两个子数组,每个数组都只包含一个所要求的元素。具体解法在这里。我就不当搬运工了。
这种题目的特点就是 其他元素一定要出现偶数次。