数组中数字出现的次数

一、需求

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

输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:

输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

二、分组异或

2.1  思路分析

  1. 异或的特点:①相同为0,相异为1;②0与任何数异或就是原数;③任何一个数字与它本身异或结果为0;④常用1 & num 与 1左移的方式来判断num二进制位中第一位1(从低位到高位算);
  2. 给定的数组中有两个不同的数字,其余为相同的数字,根据异或特点③,所有数字异或的结果就是这两个不同数字的异或,我们无法从这两个不同数字的异或结果中找到这两个数字,因此需要分组;
  3. 那么如何分组呢?两个不同数字的异或结果中必然有1,我们根据异或特点④,找到为1的那一位,这两个数字在这一位,必然有一个为1,有一个为0
  4. 假设第2位为1(从低位到高位算),则记mask = 0010(假设这里的二进制位数总共为4),使用mask与数组中的每个元素进行运算,那么数组中的每个元素的二进制位在第2位(从低位到高位算)不是0就是1,其结果要么为0,要么为1,因为两个不同的数字在该位不同,故可分成两组;
  5. 对于数组中的相同元素,要么两个相同的数在第2位(从低位到高位算)均为0,要么两个相同的数在第2位(从低位到高位算)均为1,它们都在相同的组;
  6. 分组过程中对每组中的值进行异或操作,最后返回每组剩下的值就是要找的两个不同的数字;

2.2  代码实现

class Solution {
    public int[] singleNumbers(int[] nums) {
        int res = 0;
        //res返回两个不同数字异或的结果
        for(int i = 0; i < nums.length; i++) {
            res ^= nums[i];
        }
        //寻找res的最低位1的位置
        int mask = 1;
        //'&'的优先级低于'=='
        while((mask & res) == 0) {
            mask <<= 1;
        }
        //开始分组
        int z1 = 0;
        int z2 = 0;
        for(int i = 0; i < nums.length; i++) {
            if((mask & nums[i]) == 0) {
                z1 ^= nums[i];
            } else {
                z2 ^= nums[i];
            }
        }
        return new int[] {z1, z2};
    }
}

2.3  复杂度分析

  • 时间复杂度为O(n);
  • 空间复杂度为O(1);

三、学习地址

作者:eddieVim

链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/jie-di-qi-jiang-jie-fen-zu-wei-yun-suan-by-eddievi/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值