题解 | #数组中只出现一次的两个数字#

数组中只出现一次的两个数字

https://www.nowcoder.com/practice/389fc1c3d3be4479a154f63f495abff8

方法一:哈希表

1、利用哈希表进行统计数字出现的频率

2、再次遍历,找到只出现一次的数字,加入创建的ArrayList数组中

3、要求非降序输出,则先比较二者的大小后输出,注意要求返回的是int【】数组,要创建此数组将得到的值作为其元素

import java.util.*;
public class Solution {
    public int[] FindNumsAppearOnce (int[] nums) {
        HashMap<Integer,Integer> mp = new HashMap<Integer,Integer>();
        //遍历数组,统计频率
        for(int i=0;i<nums.length;++i){
            if(!mp.containsKey(nums[i])){
                mp.put(nums[i],1);
            }else{
                mp.put(nums[i],mp.get(nums[i])+1);
            }
        }
        //再次遍历,寻找只出现一次的数
        ArrayList<Integer> res = new ArrayList<Integer>();
        for(int i=0;i<nums.length;++i){
            if(mp.get(nums[i])==1){
                res.add(nums[i]);
            }
        }
        // 非降序输出,只有两个数,比较后返回
        if(res.get(0)<res.get(1)){
            return new int[] {res.get(0),res.get(1)};
        }else{
            return new int[] {res.get(1),res.get(0)};
        }
        
    }
}

方法二:位运算之异或运算

异或运算有个特点是能抵消相同的元素,即 a⊕b⊕c⊕b⊕c=a,任何数和0异或还是数字本身。正好题目中其他数字出现两次,两个特殊的数字出现一次,将所有数异或,结果就是两个特殊的数的异或值a⊕b,最后要分别取出两个特殊值。

0^0=0,0^1=1,1^0=1,1^1=0

根据a⊕b的结果中如果二进制第一位是1,则说明a与b的第一位二进制不相同,否则则是相同的,从结果二进制的最低位开始遍历,总能找到二进制位为1的情况:

0&0=0,0&1=0,1&0=0,1&1=1

1

2

3

//找到两个数不相同的第一位

while((k & temp) == 0)

k <<= 1;

因为两个数字不相同,我们就以这一位是否为1来划分上述的两个数组,相同的数字自然会被划分到另一边,经过异或运算都抵消,而a与b也会刚好被分开。

1

2

3

4

5

//遍历数组,对每个数分类

if((k & array[i]) == 0)

res1 ^= array[i];

else

res2 ^= array[i];

具体做法:

  • step 1:遍历整个数组,将每个元素逐个异或运算,得到a⊕b。
  • step 2:我们可以考虑位运算的性质,通过与运算从低位开始找到二进制中第一个不相同的位,即与运算结果为1的位(这是前面异或运算的结果,只有当1^0时结果才为1)
  • step 3:遍历数组,根据前面判断的第一个不相同的位置是否为1,可以将所有数组划分成两组,对分开的数组单独作异或连算,结果就是两个不同的值。
  • step 4:最后整理两个数的次序再输出。

代码如下:

import java.util.*;
public class Solution {
    public int[] FindNumsAppearOnce (int[] nums) {
        int res1=0;
        int res2=0;
        int temp=0;
	  //全部异或,得到两个数的异或值
        for(int i=0;i<nums.length;++i){
            temp^=nums[i];
        }
        int k=1;  //记录从低位起第一个不相同的位
        while((k&temp)==0){//结果为0,表示该位相同
            k<<=1;  //左移一位,继续比较
        }
	  //再次遍历数组,将其按k的最高位划分为两组
        for(int i=0;i<nums.length;++i){
            if((k&nums[i])==0){  //该位为0是一组
                res1^=nums[i];  //最后结果只有一个数
            }else{  //该位为1是一组
                res2^=nums[i];  
            }
        }
        if(res1<res2){
            return new int[]{res1,res2};
        }else{
            return new int[]{res2,res1};
        }
        
    }
}
全部评论

相关推荐

03-29 17:05
门头沟学院 Java
asdasdasda...:我前段时间找工作焦虑,有几天连续熬夜熬穿了,然后心脏突然不舒服,立马躺床上睡觉了,然后第二天还是不舒服,去看医生说是心率不齐,吓得我后面天天早早睡觉,调养身体,过了好几天才好过来。所以真的,工作这些东西哪有那么重要,最多钱多一点钱少一点,降低物欲。活着才是最重要的,现在想想真的后怕
如何排解工作中的焦虑
点赞 评论 收藏
分享
04-02 10:09
门头沟学院 Java
用微笑面对困难:这里面问题还是很多的,我也不清楚为啥大家会感觉没啥问题。首先就是全栈开发实习9个月的内容都没有java实习生的内容多,1整个技术栈没看出太核心和难点的内容,感觉好像被拉过去打杂了,而且全栈基本上很容易被毙。里面能问的bug是在太多了比如L:继承 BaseMapper 可直接使用内置方法’。请问你的 BaseMapper 是如何扫描实体类注解如果瞬时产生 100 个上传任务,MySQL 的索引设计是否会有瓶颈?你做过分库分表或者索引优化吗?全栈的内容可以针对动态难点去搞,技能特长写在下面吧,你写了这么多技能,项目和实习体现了多少?你可以在项目里多做文章然后把这个放下去,从大致来看实习不算太水,有含金量你也要写上内容针对哨兵里面的节点变化能问出一万个问题,这个很容易就爆了。
提前批简历挂麻了怎么办
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务