利用位運算判斷陣列中是否有重複的數字
阿新 • • 發佈:2019-02-09
討論這個主題的來由是《劍指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]);