每天一道LeetCode-----一个整数序列,每个元素出现两次,只有一个(两个)出现一次,找到这个(这两个)元素
Single Number
原題鏈接Single Number
一個整數序列,每個數字都出現兩次只有一次數字出現了一次,找到只出現一次的那個數字
位運算的異或算法有如下幾個性質
- 值相同的兩個數字異或結果為0,即a ^ a = 0
- 交換律,即a ^ b = b ^ a
- 綜上兩條性質,得到a ^ b ^ b = b ^ a ^ b = b ^ b ^ a = a
所以只需要遍歷一遍序列,并做異或運算,所有出現兩次的數字在異或的過程中都變為0,只留下唯一的一個出現一次的數字
代碼如下
class Solution { public:int singleNumber(vector<int>& nums) {return std::accumulate(nums.begin(), nums.end(), 0, bit_xor<int>()); } };Single Number II
原題鏈接Single Number II
一個整數序列,每個數字都出現三次只有一個數字出現了一次(也可以出現一次或兩次),找到這個數字
利用上面異或的思想,找到某種運算使得三次計算結果后為0,一次和兩次的計算結果和數字本身相同,本質上還是采用bitmap的思想
采用兩個整數變量a和b,如果a的某一位是1,代表目前為止這一位出現了1次,如果b的某一位是1,代表到目前為止這一位出現了2次,a和b對應位置上都為0表示這一位出現了0次或3次(因為需要保證三次運算結果為0)
僅僅觀察一位的話,有如下的轉換關系,其中c是當前遍歷到的數字的對應位,a’和b’是更新后的a和b
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 |
| 0 | 1 | 0 | 0 | 1 |
| 0 | 1 | 1 | 0 | 0 |
找到a’和b’的運算式子,即將a’為1和b’為1的情況分離出來
| 0 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 |
| 1 | 0 | 1 | 1 |
| 0 | 1 | 0 | 1 |
得到運算式
a' = ((~a) & (~b) & c) | (a & (~b) & (~c)); b' = (a & (~b) & c) | ((~a) & b & (~c));最后,a’表示出現一次的數字,b’表示出現兩次的數字
代碼如下
class Solution { public:int singleNumber(vector<int>& nums) {int a = 0, b = 0;for(auto& c : nums){int tmpa = ((~a) & (~b) & c) | (a & (~b) & (~c));int tmpb = (a & (~b) & c) | ((~a) & b & (~c));a = tmpa;b = tmpb;}return a | b;} };Single Number III
原題鏈接Single Number III
一個整數序列,每個數字都出現了兩次只有兩個數字出現了一次,找到這兩個數字
兩個出現一次的數字不能簡單的使用異或找到,但是考慮一下,假設a, b分別是這兩個只出現一次的數字,c1, c2, …, cn代表其他的數字,那么
a, c1, c2, …, cn這個序列可以采用問題一的解法求得a(異或一遍)
b, c1, c2, …, cn這個序列同樣可以采用問題一的解法
但是要怎樣分離出a和b呢,如果最開始異或一遍整數序列,那么得到的結果就是a ^ b的值,由于a和b肯定不相等,那么a ^ b != 0,這就會導致結果中肯定有一位是1,哪一位都可以,不過最好找的是最右邊的1,即
int diff = a ^ b; diff = (diff) & (~(diff - 1));此時diff只有一位是1,且這一位的1是整個diff中最右邊的1。那么就可以采用這個diff區分a和b,因為a和b一定有一個該位是1,有一個該位是0,才可以在異或結果中使得該位是1
剩下的工作仍然是異或一遍序列即可,代碼如下
class Solution { public:vector<int> singleNumber(vector<int>& nums) {vector<int> res{0, 0};int diff = std::accumulate(nums.begin(), nums.end(), 0, bit_xor<int>());diff = (diff) & (~(diff - 1));for(auto& num : nums){/* 這里無需考慮其他數字與diff的異或結果,因為他們都是成對出現的,異或不異或都無所謂 */if(diff ^ num == 0){res[0] ^= num;}else{res[1] ^= nums;}}return res;} };這三道題主要考察的是對位運算的掌握,尤其是位操作,本質上是bitmap思想,用每一位表示出現的情況
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的每天一道LeetCode-----一个整数序列,每个元素出现两次,只有一个(两个)出现一次,找到这个(这两个)元素的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每天一道LeetCode-----分糖果
- 下一篇: 每天一道LeetCode-----复制一