[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章