LeetCode(41) Single Number I 和 II
Single Number I
題目描述
Given an array of integers, every element appears twice except for one. Find that single one.
如果一個給定陣列中除了一個元素其他所有元素均出現了兩次,這裡讓我們找到只出現了一次的元素。
解題方法
這裡需要使用位運算來解決本題。我們知道異或運算有這樣的結果a^a = 0,所以對陣列中所有元素進行異或運算時,相等的兩個元素為相互抵消為0,剩下的即是隻出現了一次的元素。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int a = nums[0];
for(size_t i=1; i != nums.size(); ++i)
{
a = a ^ nums[i];
}
return a;
}
};
從程式碼中可以看到我們沒有這這裡做邊界條件處理(陣列長度為0),因為本題題目中說明了該情況不會發生,所以我們使a = nums[0]。
Single Number II
題目描述
Given an array of integers, every element appears three times except for one. Find that single one.
不同於第一題,除了一個數其他數字均是出現兩次,第二題中其他數字均是出現三次。因此第二題不能像第一題一樣簡單的使用異或運算得到結果。但我們依然可以使用位運算的思路去解決本題。
如果一個數字出現了三次,那這個數字轉為二進位制時,為1的位置上出現的次數也是3的倍數。因此我們可以統計每一位上的出現次數是否為3的倍數,如果不為3的倍數則說明只出現一次的數字上該位為1。
解題程式碼
class Solution {
public:
int singleNumber(vector<int>& nums) {
vector<int> count(32 , 0);
for(size_t i = 0; i != nums.size(); ++i)
{
int num = nums[i];
int place = 0;
for(size_t j = 0; j != 32; ++j)
{
if(num & 1) count[j]++;
num = num >> 1;
}
}
int result = 0;
for(size_t i = 0; i != count.size(); ++i)
{
if(count[i] % 3 != 0)
{
int bit = 1;
int j = i;
while(j)
{
bit = bit << 1;
j--;
}
result = bit | result;
}
}
return result;
}
};
這裡統計次數的時候,進行了32次的迴圈是因為int型別由4 byte即32組成,而不是直接使用while迴圈若num不為0則迴圈進行右移操作是因為num可能為負值,在進行右移的時候會進行符號位的負值,而造成死迴圈。
補充知識:
在C++中對一個數進行右移根據符號位是否會被複制有算術右移和邏輯右移兩種情況。例如一個8 bit的數字如果符號位為1(負數)如a = 10000111;
- 算術右移 a >> 1 -> 11000011:這裡右移後高位補充符號位;
- 邏輯右移 a >> 1 -> 01000011:這裡右移後高位補0;
一般在C++中都是預設為算術右移,所以如果使用下面這種形式進行右移時,如果num符號位為1(負數)則會造成死迴圈。所以在我們的實現中直接通過32次位移判斷每一位上是0還是1。
while(num)
{
num = num >> 1;
}