[leetcode] Single Number系列

Single Number

题目链接 https://leetcode.com/problems/single-number/
题目:Given an array of integers, every element appears twice except for one. Find that single one.即,除了1个数以外,其他数字均出现2次,找出那个只出现1次的数字。
方法:
(1) 最容易想到的是扫一遍数组,用无序哈希表保存每个数字出现的次数,输出只出现1次的数字;虽然时间为线性复杂度,但空间也是O(n)。
(2) 考虑异或运算的性质,0^0 =0, 0^1 = 1, 1^0 = 1, 1^1 = 0,则易知 a^a = 0, 0^a = a. 由于数组中除去某元素外所有元素均出现2次,那么将数组元素全部异或后的结果即为所求的元素。

Single Number II

题目链接 https://leetcode.com/problems/single-number-ii/
题目:Given an array of integers, every element appears three times except for one. Find that single one. 即,除了1个数以外,其他数字均出现3次,找出那个出现次数不到3的元素 x 。
方法:
(1) 扫描数组,记录每个数字出现的次数依然可行,但空间消耗为O(n)。
(2) 按位扫描数组中的每一个元素,若该位上1的数目可被3整除,则所求元素 x 该bit为0,否则为1。其时间复杂度其实为O(8*sizeof(int)*n)。
代码如下:

int singleNumber(vector<int>& nums) {
     int ret = 0;
     int bitnum = 8*sizeof(int);
     //cout << bitnum << endl;
     for(int i=0; i<bitnum; ++i){
         int cnt = 0;
         for(int j=0; j<nums.size(); ++j){
             if((nums[j] >> i) & 1){
                 ++ cnt;
             }
         }
         if(cnt % 3){
             ret |= (1 << i);
         }
     }
     return ret;
}

(3) 进一步思考第2种方法,我们可以记录每一位上1出现的次数,当出现次数达到3时,则将该位置0,最后将出现次数为1和出现次数为2的位组合起来即为所求元素。代码如下:

int singleNumber(vector<int>& nums) {
     int one = 0, two = 0, three = 0;
     for(int i=0; i<nums.size(); ++i){
         three = nums[i]&two;
         two |= (one&nums[i]);
         // 之前出现过1次的bit,在nums[i]中再次出现的话,其出现次数不是1,应置0,故做异或运算
         one ^= nums[i];
         // 将出现3次的bit置0
         one &= ~three;
         two &= ~three;
     }
     return one|two;
}

Single Number III

题目链接:https://leetcode.com/problems/single-number-iii/
题目: Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
For example: Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].
方法:
(1) 依然可以通过扫描数组,记录每个元素出现的次数。
(2) 假设只出现1次的两个元素分别为a, b,这次如果将数组中全部元素进行异或的话,得到的是a^b的值,
如何进一步计算a和b呢?想办法将问题转化成第一题的形式:全部元素均出现2次,除了其中1个元素。a与b异或之后,相同的位被置为0,不同的位为1,我们可以利用其中一个不同的 bit 将数组元素分成两部分,这样每个部分都是一个问题一 。代码如下:

vector<int> singleNumber(vector<int>& nums) {
     vector<int> ret(2,0);
     int x = 0;
     for(int i=0; i<nums.size(); ++i){
         x ^= nums[i];
     }
     x &= ~(x-1);  // 保留x二进制表示中最后一个1,其他bit置0
     for(int i=0; i<nums.size(); ++i){
         if(nums[i] & x){
             ret[0] ^= nums[i];
         }else{
             ret[1] ^= nums[i];
         }
     }
     return ret;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章