1. 程式人生 > >利用位運算判斷陣列中是否有重複的數字

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

討論這個主題的來由是《劍指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]);