zoukankan      html  css  js  c++  java
  • 剑指offer-56数组中数字出现的次数

    题目

    一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字要求时间复杂度是O(n),空间复杂度是O(1)。

    • 输入:nums = [4,1,4,6]
    • 输出:[1,6] 或 [6,1]

    其实看到他要求的空间复杂度为O(1)代表不能使用类似于HashMap这种数据结构的解法了,我当时也有点懵比,那要怎么做呢?想了半天还是看看评论区大神的解题思路吧。

    思路

    在做这道题之前你需要知道 异或运算符的性质。也就是^
    异或:相同为0,不同为1
    举个例子:3 ^ 5

    3的二进制:0 0 1 1
    5的二进制:0 1 0 1
    异或结果: 0 1 1 0

    异或满足交换律,结合律,自反性

    • 交换律:a ^ b = b ^ a
    • 结合律:(a ^ b) ^ c = a ^ (b ^ c)
    • 自反性: A XOR B XOR B = A xor 0 = A
    • x ^ x = 0 ; x ^ 0 = x(任何数与他自身做异或等于0,任意数与0做异或还是他本身)

    由此结合题目我们可以从数字的异或入手。

    因为只有两个数字只出现过一次,其余的数都出现了两次,所以对这个数组中的所有数字进行异或操作的结果也就是对 只出现一次的两个数进行异或。我们把这俩数字异或的结果设为 res.

    现在关键是怎样把他们分开?
    因为两个数字如果相同,那么他们的二进制的每一位都相同,如果两个数不同,那么他们的二进制中肯定有不同的那一位。

    由于异或的性质是,同一位相同则为 0,不同则为 1. 我们将所有数字异或的结果一定不是 0,也就是说至少有一位是 1.

    我们随便取一个,分组的依据就来了, 就是你取的那一位是 0 分成 1 组,那一位是 1 的分成一组。

    方法一:

    int h = 1;
    while((h&res)==0){
    	h=h<<1;
    }
    //从res中找第一个不是0的那一位(从右往左)
    

    方法二:

    int h = res&(-res);
    //这个需要试一下,相反数的二级制计算时:先取反,再加一,在进行&就能找到res的二级制中第一个 1
    //例如 5 的二进制是 0101 -5的二进制是 1011 进行&得到 0001,所以从右往左,5的二进制的第一位是 1.
    

    我们将这两个分开以后,只需要进一步判断数组中的元素和 h 做与 运算

    如果n(这里指数组中的元素)& h == 0,代表当前元素的这一位上是0,
    如果 (n & h )==n那么就代表当前元素这一位上是1,这样就把整个数组分开了,同时两个只出现一次的数字也分开了。

    分成两组后,最后进行异或运算,剩余的结果就分别是只出现1次的那两个数。(因为 x ^ x = 0, x ^ 0 = x)

    代码

    public int[] singleNumbers(int[] nums) {
            int res = 0;// 用来保存两个只出现一次的数的异或结果
            for(int i: nums){
                res^=i;
            }
            int h=res&(-res);//从右往左找到第一个是1的位
    
            int a=0,b=0;//用来保存分组后的结果
    
            for(int n:nums){
                if((n & h)==0){
                    a^=n;
                }else{
                    b^=n;
                }
            }
            return new int[]{a,b};
        }
    

    以上有理解不到位的地方欢迎各位指出!

  • 相关阅读:
    简单的Servlet结合Jsp实现请求和响应以及对doGet和doPost的浅析
    My1stServlet
    Myeclipse发布第一个jsp页面及web project部署到tomcat上的几种方法
    java中循环的不同终止方式
    Mybatis学习笔记
    python 进程间的数据交互
    python 进程
    python 队列
    python 多线程
    python paramiko 向linux执行命令和发送接收文件
  • 原文地址:https://www.cnblogs.com/dataoblogs/p/14121925.html
Copyright © 2011-2022 走看看