59.數組中值出現了一次的數字
題目鏈接
題目描述
給定一個數字arr,其中只有有兩個數字出現了奇數次,其它數字都出現了偶數次,按照從小到大順序輸出這兩個數。
輸入描述:
輸入包含兩行,第一行一個整數n(1≤n≤105),代表數組arr的長度,第二行n個整數,代表數組arr,arr[i]為32位整數。
輸出描述:
輸出出現奇數次的兩個數,按照從小到大的順序。
示例1
輸入
4 1 1 2 3
輸出
2 3
示例2
輸入
6 11 22 11 23 23 45
輸出
22 45
備注:
時間復雜度O(n)O(n),額外空間復雜度O(1)O(1)。
關鍵技術
- 按位異或。
- 左移。
題目分析
- 用換行符分割出n,用空格分割出arr;
- 相同的數字取異或為0,不同的數字取異或為1,所以arr中所有數字的異或(sum)為兩個出現奇數次的數字(str_1,str_2)的異或,即sum = str_1 ^ str_2;
- 在sum中為1的位置上,str_1和str_2必不相等,一個為1,一個為0。(若sum為11001,那么在k=0,1,4時,str_1的第0位,第1位和第4位與str_2的第0位,第1位和第4位上的數字不相等;
- 若想取出第一個不相等的位置(在上邊例子中,k=0),即找出sum中第一個1出現的位置,此位置賦給k;
- 通過判斷k位置上是否為1,可以把數字分成兩組,一組是k位置上為1,另一組是k位置上不為1;
- 此時分別找兩組數中出現奇數次數的數,即第一組中有一個數出現了奇數次,第二組中有一個數出現了奇數次。
- 一組數中,有一個數出現奇數次,那么這組數異或以后的數就是出現奇數次的數。
- 分別求出兩組數的異或值后,排序輸出。
var input = []; var res = []; while(input = readline()){ res += input + '\n'; } //用換行符分割出n var n = res.split('\n')[0]; //用空格分割出arr var arr = res.split('\n')[1].split(' '); var sum; for(let i=0;i<n;i++){ sum ^= arr[i]; } var s_1, s_2; var k = 0; //取出第一個為 1 的下標 while(!(sum & 1)){ sum = sum >> 1; k++; } //找出出現了奇數次的數 for(let i=0;i<n;i++){ if((arr[i] >> k) & 1){ s_1 ^= arr[i]; }else{ s_2 ^= arr[i]; } } //按從小到大順序輸出 print(s_1 < s_2 ? s_1:s_2,s_1 > s_2 ? s_1:s_2);