利用位運算判斷陣列中是否有重複的數字

li27z發表於2017-03-19

討論這個主題的來由是《劍指offer》上的一道題目:
這裡寫圖片描述

解題思路:
只要滿足條件
1)陣列的長度為5;
2)陣列中的最大值減去最小值小於5(最大值、最小值不取0);
3)除0外沒有重複的數字。
這個陣列就是連續的,即可組成順子。

程式碼如下:

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size() != 5)
            return false;
        int min = 14;  // 設定最小值的初始值
        int max = -1;  // 設定最大值的初始值
        int flag = 0;  // flag用於判定陣列中是否有重複值
        for(int i = 0; i < 5; i++){
            // 根據題意,數字的範圍為1-13,若不在此範圍則返回false
            if(numbers[i] < 0 || numbers[i] > 13)
                return false;
            if(numbers[i] == 0)
                continue;
            // 判斷數字是否重複
            if(((1 << numbers[i]) & flag) > 0) 
                return false;
            flag |= (1 << numbers[i]);
            if(numbers[i] > max)
                max = numbers[i];
            if(numbers[i] < min)
                min = numbers[i];
            // 判斷最大值與最小值的差是否小於5
            if(max - min > 4)
                return false;
        }
        return true;
    }
};

我們用到了位運算來判斷陣列中是否存在重複值,它的原理簡單且實用:
因為我們的數字範圍為1-13,用每一個bit對應一個數字,如果出現過,那麼flag上這個bit就為1,不然就是0,且用一個32bit的int型足夠容納下所有位。

再回過頭來看程式碼:

// 將1右移numbers[i]位,然後與flag進行按位與運算
// 若flag上的第numbers[i]已為1,說明該位已被佔用,數字重複了,運算的結果大於0,返回false
if(((1 << numbers[i]) & flag) > 0) 
    return false;

// 通過“或操作”填充flag中不同的二進位制位
flag |= (1 << numbers[i]);

相關文章