題目和上題類似,這里給的數組僅有一個數出現一次,其他的出現3次。返回那個出現一次的數。
這題還是比較難想到的。不想上一題只要異或一下就可以了,不用額外操作。
法一:還是用map方法
class Solution { public: int singleNumber(int A[], int n) { unordered_map<int , int> umap; for (int i = 0; i < n; i++) { umap[A[i]]++; } for (int i = 0; i < n; i++) { if (umap[A[i]] == 1) return A[i]; } } };
法二:還是利用位運算才有辦法實現不用額外空間,就是遍歷32次每次記錄某位的出現的次數,如果不能被三整除,說明那個出現一次的就在該位有值,那么ans 或該位一下就可以了。
int singleNumber(int A[], int n) { int ans = 0; for (int i = 0; i < 32; i++) { int cnt = 0, bit = 1 << i; for (int j = 0; j < n; j++) { if (A[j] & bit) cnt++; } if (cnt % 3 != 0) ans |= bit; } return ans; }
法三:還是位運算,這里利用二進制模擬a進制的方法。對於此題,a為3.
點這里分析和拓展的很好:
對於除出現一次之外的所有的整數,其二進制表示中每一位1出現的次數是3的整數倍,將所有這些1清零,剩下的就是最終的數。用ones記錄到當前計算的變量為止,二進制1出現“1次”(mod 3 之后的 1)的數位。用twos記錄到當前計算的變量為止,二進制1出現“2次”(mod 3 之后的 2)的數位。當ones和twos中的某一位同時為1時表示二進制1出現3次,此時需要清零。即用二進制模擬三進制計算。最終ones記錄的是最終結果。
int singleNumber(int A[], int n) { int ones = 0, twos = 0, xthrees = 0; for(int i = 0; i < n; ++i) { twos |= (ones & A[i]); ones ^= A[i]; xthrees = ~(ones & twos); ones &= xthrees; twos &= xthrees; } return ones; }
該文的拓展很值得學習!