lintcode 落單的數(位操作)


題目1 落單的數

  給出2*n + 1 個的數字,除其中一個數字之外其他每個數字均出現兩次,找到這個數字。

  鏈接:http://www.lintcode.com/zh-cn/problem/single-number/

樣例

  給出 [1,2,2,1,3,4,3],返回 4

挑戰

  一次遍歷,常數級的額外空間復雜度

解決方案

  方法1思路:將所有的數轉換成二進制,因為是int類型,共32位。申請常數級(32位)的額外空間,然后每個數對應的位相加,最后對應位上的和模2。最后的結果就是單個數對應的二進制數。

class Solution {
public:
    /**
     * @param A: Array of integers.
     * return: The single number.
     */
    int singleNumber(vector<int> &A) {
        // write your code here
        int ans[35];
        memset(ans, 0, sizeof(ans));
        for(int i=0; i<A.size(); ++i){
            for(int k=0; k<32; k++)
                ans[k] = (ans[k]+((A[i]>>k)&1))%2;
        }
         
        int ret = 0;
        int base = 1;
        for(int i=0; i<32; ++i){
            ret += ans[i]*base;
            base *= 2;
        }
        return ret;
    }
};

  方法2思路:通過異或,相同的數結果為0,那么最后的結果一定是落單的數字。

class Solution {
public:
    /**
     * @param A: Array of integers.
     * return: The single number.
     */
    int singleNumber(vector<int> &A) {
        // write your code here
        int ans = 0;
        for(int i=0; i<A.size(); ++i)
            ans ^= A[i];
        return ans;
    }
};

題目2 落單的數 II

  給出3*n + 1 個的數字,除其中一個數字之外其他每個數字均出現三次,找到這個數字。

  鏈接:http://www.lintcode.com/zh-cn/problem/single-number-ii/

樣例

  給出 [1,1,2,3,3,3,2,2,4,1] ,返回 4

挑戰

  一次遍歷,常數級的額外空間復雜度

解決方案

  同上一題的方法1一樣的思路。

class Solution {
public:
    /**
     * @param A : An integer array
     * @return : An integer 
     */
    int singleNumberII(vector<int> &A) {
        // write your code here
       
        int ans[35];
        memset(ans, 0, sizeof(ans));
        for(int i=0; i<A.size(); ++i){
            for(int k=0; k<32; k++)
                ans[k] = (ans[k]+((A[i]>>k)&1))%3;
        }
         
        int ret = 0;
        int base = 1;
        for(int i=0; i<32; ++i){
            ret += ans[i]*base;
            base *= 2;
        }
        return ret;
    }
};

 

題目3:落單的數 III

  給出2*n + 2個的數字,除其中兩個數字之外其他每個數字均出現兩次,找到這兩個數字。

  鏈接:http://www.lintcode.com/zh-cn/problem/single-number-iii/

樣例

  給出 [1,2,2,3,4,4,5,3],返回 1和5

挑戰

  O(n)時間復雜度,O(1)的額外空間復雜度

解決方案

      

  如上圖所示,所有數的異或的結果等於兩個落單數異或的結果(設為S)。如何根據這個異或的結果將落單的數找出來呢?首先,S的值一定不為0,那么找到S對應的二進制數值為1的位(找到任意一個位為1都行, 這里我們找到S的二進制最后一個為1的位,設為P),根據這一個位置,將所有的數划分成兩部分,一部分是對應二進制P位是1,另一部分對應二進制P位是0。這樣就把兩個落單的數划分到了不同的集合里去了。如上圖的紅色框集合和綠色框集合。然后就轉換成“2*m+1個數字,除了一個數字其他數字均出現兩次”的問題,也就是題目1:落單的數I

class Solution {
public:
    /**
     * @param A : An integer array
     * @return : Two integers
     */
     
    int findNum(int k, vector<int> &A, bool flag){
        int ret = 0;
        for(int i=0; i<A.size(); ++i){
            if(flag && (1<<k)&A[i])
                ret ^= A[i];
            if(!flag && !((1<<k)&A[i]))
                ret ^= A[i];
        }
        return ret;
    }
    vector<int> singleNumberIII(vector<int> &A) {
        // write your code here
        int x = 0;
        for(int i=0; i<A.size(); ++i)
            x ^= A[i];
        int k = 0;
        for(k; k<32; ++k)//找到異或值最后一個1,說明該位置P之后,兩個不同的數對應的二進制是相同的
            if((1<<k)&x)
                break;
      //根據這個位置P,轉換成“2*m+1個數字,除了一個數字其他數字均出現兩次”的問題
      //將位置P上對應為1的數字異或得到一個數字,然后再將位置P上對應為0的數字異或得到一個數字,最后得到答案
        vector<int> ans;
        ans.push_back(findNum(k, A, true));
        ans.push_back(findNum(k, A, false));
        return ans;
    }
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM