LeetCode-137:Single Number II (只出現一次的數字)
阿新 • • 發佈:2019-01-03
題目:
Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.
Note:
- Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
例子:
Example 1:
Input: [2,2,3,2]
Output : 3
Example 2:
Input: [0,1,0,1,0,1,99]
Output: 99
問題解析:
給定一個非空整數陣列,除了其中一個元素外,其餘每個元素均出現三次。找出這個只出現一次的元素。
連結:
思路標籤
位運算、狀態機
解答:
- 和LeetCode 136:Single Number屬於類似的問題,136中給出其他元素均出現兩次,我們使用“異或”運算,即:
0^a=a
、a^a=0
,即可求得結果; - 但是當元素上升到3個及3個以上時,就無法繼續使用這麼簡單的方法來實現了,下面給出三種實現方法,其中後面的兩種是相同的,同時第一種和最後一種方法對於任意一個重複K次的相似問題均是通用的。
1. 統計每一位1的個數,和對3取餘
- 對每個整數以32位表示,分別統計每一位上1的個數,最後該位數上的和對3取餘數;
- 如果餘數不為0,則說明該位上只出現一次的元素,在該位上有1;
- 通過移位操作和1做位與運算,則可求得當前元素在該位是否有1。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for(int i=0; i<32; ++i){
int sum = 0;
for (int j=0; j<nums.size(); ++j){
sum += (nums[j]>>i) & 1;
}
ret |= (sum % 3)<<i;
}
return ret;
}
};
2. 狀態機法,用2個數分別表示狀態機的3個狀態
- 利用狀態機表示:我們用下面的三種狀態來表示對於某個數字出現了多少次:00、01、10、00,也就是我們累加的過程0——>1——>2——>0,當滿3個數字時則記為0次。
- 所以,我們可以用兩個整數(32位)來表示所有數中每一位上出現1的次數。例子:ones的第3位為1,twos的第3位為0,則表示當前累計的所有元素中,各個元素的第3位上出現1的個數為2個。
- 寫出對應關係:
- 00 (+) 1 = 01
- 01 (+) 1 = 10
- 10 (+) 1 = 00 ( mod 3)
- 那麼我們用ab來表示開始的狀態,對於加1操作後,得到的新狀態的ba(其中a表示倒數第一位,b表示倒數第2位)的演算法如下:
- a = a xor r & ~b;
- b = b xor r & ~a;
- 因為我們最後要求的是隻出現1次的元素,所以通過對所有元素的位運算後,32個位上出現1只有一次的元素就是我們要返回的元素,也就是ones當前儲存的元素。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ones = 0, twos = 0;
for(int i=0; i<nums.size(); ++i){
ones = (ones^nums[i]) & ~twos;
twos = (twos^nums[i]) & ~ones;
}
return ones;
}
};
3. 狀態機法,用K-1個數分別表示狀態機的K個狀態(通法)
- 下面的解法是與解法2同樣思想的解法,但其可以解決任意K個重複元素的問題。
- 同時,對於不同的K,假設只有一個元素重複3次,其餘重複K次,K>3,那麼我們還可以用下面的方法返回
bits[2]
來得到該返回元素,具體就不展開分析。
class Solution {
public:
int singleNumber(vector<int>& nums) {
return singleNumber(nums, 3);
}
int singleNumber(vector<int>& nums, int _K) {
int K = _K - 1;
int bits[K] = {0};
for (int num : nums) {
for (int i = 0; i < K; i++) {
int mask = -1;
for (int j = 0; j < K; j++) if (j != i)
mask &= ~bits[j];
bits[i] = (bits[i] ^ num) & mask;
}
}
return bits[0];
}
};