博客
关于我
剑指offer打卡Day14:数组中只出现一次的数字
阅读量:352 次
发布时间:2019-03-04

本文共 3340 字,大约阅读时间需要 11 分钟。

剑指offer打卡Day14:数组中只出现一次的数字

题目描述

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

解析:

  • 看到题目的时候确实 有点轻敌了:

    • 乍一看题目,哟吼,这不是就简单的数组计数器就可以搞定了吗?

    • 然后一顿哐哐操作写好算法与测试类:

      @Testpublic void ttest1() {           int arr[] = {       1, 1, 2, 2, 3, 4, 4, 5};  System.out.println(Arrays.toString(FindNumsAppearOnce_MyTest(arr)));}//num1,num2分别为长度为1的数组。传出参数//将num1[0],num2[0]设置为返回结果public int[] FindNumsAppearOnce_MyTest(int[] array) {           int[] ints = new int[array.length];    int[] result = new int[2];    int count = 0;    for (int anArray : array) {               ints[anArray]++;    }    for (int i = 0; i <array.length; i++) {               if (ints[i]==1){                   result[count++]= i;        }    }    return result;}/*输出结果:[3, 5]稳了,没毛病。*/
    • 结果将算法稍作改写丢到牛客网上:

      //num1,num2分别为长度为1的数组。传出参数//将num1[0],num2[0]设置为返回结果public class Solution {           public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {               int[] ints = new int[array.length];        int count = 0;        for (int i = 0; i < array.length; i++) {                   ints[array[i]]++;        }        for (int i = 0; i <array.length; i++) {                   if (ints[i]==1){                       count++;                if (count == 1) {                           num1[0] = i;                } else {                           num2[0] = i;                }            }        }     }}

      顿时报错:
      在这里插入图片描述
      大意了啊😓 实在妹又想到还有这么大的数字,这对int[]数组来说确实是不可行的。也就是说用数组计数器的方法不够全面。

  • 不能用数组计数器做那得咋整啊?

    • 仔细审题,题目中说寻找只出现一次的数字

    • 众所周知,Map中的key是不能重复的,如果重复是会自动覆盖前者,因此我们可以利用HashMap进行操作(见解答一)

      • 本题知识点:

  • 不过遍历多次总感觉可以继续优化,查阅资料:

    • 对于查找只出现一次的问题可以用 ^ 异或 运算进行解决

      异或的性质:对于整数a,有(1)a^a=0(2)a^0=a(3)a^b^c=a^(b^c)=(a^c)^b
    • 因此首先将数组异或运算一次后会出现一个结果:

      根据上述公式(3)是只出现一次的两个数(A^B的结果),这个结果的二进制中的1,表现的是A和B两个数字在二进制上的不同位。

      int result = 0;for (int i = 0; i < arr.length; i++) {           result ^= arr[i];}System.out.println(result);
    • 接下来就是如何将(A^B)的结果拆分为A和B

      • (A^B)表现的是A和B的不同的位
      • 我们就取第一个1所在的位数(可以左移)
      • 假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。
      • 遍历一次后,由于相同数字所有位都相同,所以相同的数肯定在一个组,而不同的数,肯定不在一组。
      • 最后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。

解答:

//解答一:哈希算法//在Map中用value标识出现的次数,用key存储元素public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {       HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();    for(int i=0; i < array.length; i++){           if(map.containsKey(array[i]))            //如果出现过一次则直接存入{`出现两次的元素`:2}            map.put(array[i],2);        else            map.put(array[i],1);    }    int count = 0;    for(int i=0; i < array.length; i++){           if(map.get(array[i]) == 1){               if(count == 0){                   num1[0] =  array[i];                count++;            }else                num2[0] =  array[i];        }    }}//解答2:运用位移和^运算public String FindNumsAppearOnce_withOperation(int [] array) {       int num1[] = new int[1];    int num2[] = new int[1];        int xor1 = 0;    for(int i=0; i < array.length; i++){           xor1 = xor1^array[i];    }    //在xor1中找到第一个不同的位对数据进行分类,分类为两个队列对数据进行异或求和找到我们想要的结果    int index = 1;    while((index & xor1)==0)        //因为可能有多个位为1所以需要求一下位置        index = index <<1;    int result1 = 0;    int result2 = 0;    for(int i=0; i < array.length; i++){           if((index & array[i]) == 0)            result1 = result1^array[i];        else            result2 = result2^array[i];    }    num1[0] = result1;    num2[0] = result2;    return num1[0]+","+num2[0];}
  • 补充个链接:

转载地址:http://oqzg.baihongyu.com/

你可能感兴趣的文章
Web基础应用 NFS服务基础 触发挂载
查看>>
DNS服务基础 特殊解析 DNS主从架构 DNS子域授权 DNS查询
查看>>
python_透视表操作unstack
查看>>
端口列表_端口占用问题解决kill_ps_net
查看>>
having和where的区别
查看>>
create-react-app路由的实现原理
查看>>
PSI值
查看>>
lift曲线
查看>>
【平庸附件】python反序列化----本地测试 -----踩坑坑坑坑坑坑注意点! 这个夭折了,可以看看那些nb的
查看>>
【java方法】代码练习——程序逻辑控制
查看>>
字符串与数组的转化的简单易懂的方法
查看>>
中缀表达式与后缀表达式
查看>>
力扣—寻找两个正序数组的中位数(Median of Two Sorted Arrays Java)
查看>>
海思Hi3531DV100开发环境搭建
查看>>
Xilinx Zynq pl353-nand使用
查看>>
JavaScript上传下载文件
查看>>
QWaitCondition把异步调用封装成同步调用
查看>>
windows驱动开发-编译错误集合
查看>>
嵌入式linux系统应用开发
查看>>
Linux驱动开发之PCIe Host驱动
查看>>