博客
关于我
剑指offer打卡Day14:数组中只出现一次的数字
阅读量:354 次
发布时间: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/

你可能感兴趣的文章
自动安装服务2
查看>>
js的各种数据类型判断(in、hasOwnProperty)
查看>>
严格模式、混杂模式与怪异模式
查看>>
HTML 和 CSS 简单实现注册页面
查看>>
(SpringMVC)springMVC.xml 和 web.xml
查看>>
(LeetCode)Java 求解搜索旋转排序数组
查看>>
ERROR 1146 (42S02): Table 'mysql.role_edges' doesn't exist
查看>>
DP - Tickets - HDU - 1260
查看>>
Spring 与使用STOMP消息
查看>>
Java Swing JList:列表框组件
查看>>
jQuery中的动画
查看>>
狂神说MySQL01:初识MySQL
查看>>
1.2.3 项目、项目集、项目组合以及运营管理之间的关系
查看>>
光环和你一起迎接改版
查看>>
【△重点△】LeetCode - 4. 寻找两个正序数组的中位数——二分查找
查看>>
LeetCode - 5. 最长回文子串——字符串、动态规划
查看>>
全局锁和表锁 :给表加个字段怎么有这么多阻碍?
查看>>
事务到底是隔离的还是不隔离的?
查看>>
@Import注解---导入资源
查看>>
解决ubuntu在虚拟机(VMware)环境下不能联网的问题
查看>>