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);
