位操作相关题目-数组中某数字只出现了一次及多种进阶版本

来源:互联网 发布:中科大软件学院 编辑:程序博客网 时间:2024/06/08 17:53

原题:

有一个数组,其中有一个数字只出现了一次,其余的数字均出现了两次,请找到该数组.

class Solution {public:int FindNumber(vector<int> vec) {int len = vec.size();if (len == 0) return -1;int res = 0;for (int i = 0; i < len; i++) {res = res^vec[i];}return res;}};

这种题目可以通过排序,或者建立哈希表查找。但排序复杂度为O(n log n),建立哈希表则是需要额外的O(n)空间复杂度。

通过位操作则可以巧妙解决该问题。


注意到,异或操作的特点: 1)两个相同的数异或结果为0, 

                                       2)与0异或得到该数本身,

                                       3) 异或操作满足交换性。

基于这两个性质,上题可以这样解决:异或遍历整个数组,则所有出现两次的数字异或之后结果为0,0与只出现了一次的数字异或结果是该数本身。

所以最终的结果就是数组中所有数字异或的结果。


进阶版:

进阶一:

一个数组中,有两个数字只出现了一次,其余的数字都出现了两次,求找到出现一次的两个数字分别是哪个


分析:如果是一个数字只出现一次,直接有原型解决。现在出现了两个只出现一次的,该如何解决呢?

          注意到,两个不同的数字异或结果不为0,即总有一位是1(也可能有多个位置为1)。正是这一位的结果构成了两个不同数之间的区别。

          根据该位置为1和为0,我们可以将原数组分为两类,一个是该位置为1的,必然包括一个只出现一次的数字和多组出现两次的数字(两个相同的数字每一位的bit表示都一样,所以必然会被分到同一类中);另一类是该位置为0的。分别对每一类做异或操作,得到结果即为所求。

#include<iostream>#include<vector>using namespace std;class Solution {public:void FindNumsAppearOnce(vector<int> data, int* num1, int *num2) {int len = data.size();if (len < 2) return;int res = 0;for (int i = 0; i < len; i++) {res ^= data[i];}int idx = FindBit1(res);*num1 = 0; *num2 = 0;for (int i = 0; i< len; i++) {if (isBit1(data[i], idx)) {*num1 = *num1 ^ data[i];}else {*num2 = *num2 ^ data[i];}}}bool isBit1(int num, int k) {   //从右边数第k位是否为bit 1int count = 1;unsigned int flag = 1;while (count < k) {flag = (flag << 1);count++;}if (flag & num) return true;return false;}int FindBit1(int num) {unsigned int flag = 1;int count = 1;while (!(num & flag)) {flag = (flag << 1);count++;}return count;}};int main(){Solution s;vector<int> vec{ 1,2,2,1,5,3,5,9 };int num1 = 0; int num2 = 0;s.FindNumsAppearOnce(vec, &num1, &num2);cout << num1 << " " << num2 << endl;return 0;}


进阶二:

一个数组中,只有一个数字出现了一次,其余的数字均出现了三次,求找到只出现一次的数字。

分析:

因为三个相同的数字异或的结果还是其本身,所以上面题目的思路无法适用此题。但可以延续位操作的思路。

对每一个出现三次的数字来说,其二进制表示完全相同,如果把二进制表示的每一位都分别加起来,则每一位的和都可以被3整除。

所以,将所有的数字二进制表示的每一位都分别加起来之后,每个无法被3整除的位都是因为只出现了一次的那个数字造成的。

#include<iostream>#include<vector>using namespace std;class Solution {public:int FindNumber(vector<int> vec) {int len = vec.size();if (len == 0) return -1;return Find(BitSum(vec), BitSum(vec).size());}vector<int> BitSum(vector<int> vec) {int len_res = sizeof(int) * 8;vector<int> res(len_res);for (int i = 0; i < vec.size(); i++) {unsigned int flag = 1;for (int j = len_res-1; j >= 0; j--) {if (vec[i] & flag) {res[j]++;}flag = flag << 1;}}return res;}int Find(vector<int> res, int length) {int num = 0;int flag = 1;for (int i = length - 1; i >= 0; i--) {if (res[i] % 3) {num += flag;}flag = flag << 1;}return num;}};int main(){Solution s;vector<int> vec{ 1,2,2,1,1,3,2};int  res = s.FindNumber(vec);return 0;}


原创粉丝点击