Given an 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?
<Solution>Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
這題是 Single Number 的衍生題
先看一種解法
- 對於每個出現在 vector 裡面的數,去計算它的出現次數
- 記算方式是使用 bit operation。將每個 int 視為 32bits,當一個數出現三次時,某個bit的位置也會出現三次1,相加起來再和3求餘數,如果不為0,就是要找的數字
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Solution { | |
public: | |
int singleNumber(vector<int>& nums) { | |
int ans = 0; | |
for(int i = 0; i < 32; i++) { | |
int sum = 0; | |
for(const auto &n : nums) { | |
//>> calculate how many times one number show up | |
//>> in the form of bit | |
sum += (n >> i) & 1; | |
} | |
ans |= (sum % 3) << i; | |
} | |
return ans; | |
} | |
}; |
用同樣的概念,來優化一下寫法
- 用三個變數來代表一個數字出現的次數,分別是出現一次、兩次和三次
- 當一個數字出現三次後,要把出現一次和兩次的變數歸零
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Solution { | |
public: | |
int singleNumber(vector<int>& nums) { | |
int one = 0, two = 0, three = 0; | |
for(const auto &n : nums) { | |
two |= one & n; | |
one ^= n; | |
three = one & two; | |
//>> reset | |
one &= ~three; | |
two &= ~three; | |
} | |
return one; | |
} | |
}; |
想法如下
- 整個狀態的轉換是,0 -> 1 -> 2 -> 0,其實就是 mod 3 會出現的三種狀態
- 要表示三種狀態,總共需要兩個 bits,其狀態轉換如下
00 -> 01,等同於 0 + 1 = 1
01 -> 10,等同於 1 + 1 = 2
10 -> 00 ,等同於 2 + 1 = 0
- 由上面的狀態轉換來推導公式,用兩個變數 one 和 two,分別代表該 bit 出現一次和兩次,也是用來表示狀態轉換的兩個 bits
- 如果number出現次數不到兩次(two = 0),那麼 one 的狀態轉換就等同於 one ^= number;如果number已經出現兩次了(two = 1),那麼 one下個狀態就是歸零,所以最後的公式為 one = (one ^ number) & ~two
- 記算完 one 之後,再計算 two(切記)。當number出現一次(one = 1),two 一定是 0,也就是 two &= ~one;當 number 出現兩次以上(one = 0),two ^= number,最後的公式就是 two = (two ^ number) & ~one
two one -> two one
0 0 -> 0 1
0 1 -> 1 0
1 0 -> 0 0code 如下(參考資料)
c++
Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Solution { | |
public: | |
int singleNumber(vector<int>& nums) { | |
int one = 0, two = 0; | |
for(const auto &n : nums) { | |
one = (one ^ n) & ~two; | |
two = (two ^ n) & ~one; | |
} | |
return one; | |
} | |
}; |
Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Solution { | |
fun singleNumber(nums: IntArray): Int { | |
var one = 0 | |
var two = 0 | |
for(n in nums) { | |
one = (one xor n) and two.inv() | |
two = (two xor n) and one.inv() | |
} | |
return one | |
} | |
} |
沒有留言:
張貼留言