牛客网刷题32—数组中值出现了一次的数字

59.数组中值出现了一次的数字

题目链接
https://www.nowcoder.com/practice/200d8d789f9f431999fac795bb094356?tpId=101&&tqId=33215&rp=5&ru=/activity/oj&qru=/ta/programmer-code-interview-guide/question-ranking

题目描述
给定一个数字arr,其中只有有两个数字出现了奇数次,其它数字都出现了偶数次,按照从小到大顺序输出这两个数。
输入描述
输入包含两行,第一行一个整数n(1≤n≤10^5),代表数组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)。
关键技术

  1. 按位异或。
  2. 左移。

题目分析

  1. 用换行符分割出n,用空格分割出arr;
  2. 相同的数字取异或为0,不同的数字取异或为1,所以arr中所有数字的异或(sum)为两个出现奇数次的数字(str_1,str_2)的异或,即sum= str_1 ^ str_2;
  3. 在sum中为1的位置上,str_1和str_2必不相等,一个为1,一个为0。(若sum为11001,那么在k=0,1,4时,str_1的第0位,第1位和第4位与str_2的第0位,第1位和第4位上的数字不相等;
  4. 若想取出第一个不相等的位置(在上边例子中,k=0),即找出sum中第一个1出现的位置,此位置赋给k;
  5. 通过判断k位置上是否为1,可以把数字分成两组,一组是k位置上为1,另一组是k位置上不为1;
  6. 此时分别找两组数中出现奇数次数的数,即第一组中有一个数出现了奇数次,第二组中有一个数出现了奇数次。
  7. 一组数中,有一个数出现奇数次,那么这组数异或以后的数就是出现奇数次的数。
  8. 分别求出两组数的异或值后,排序输出。
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);

你可能感兴趣的:(刷题)