LeetCode 260.Single Number III(只出现一次的数 III)

题目

LeetCode: 260. Single Number III

力扣: 260. 只出现一次的数字 III

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

Example:

Input:  [1,2,1,3,2,5]
Output: [3,5]

Note:

  1. The order of the result is not important. So in the above example, [5, 3] is also correct.

    结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。

  2. Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

    你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?


解析

大致思路:

  • 利用XOR异或运算的运算性质a^0 = a, a^b^b = a, a^b = b^a,对原始数组中的所有数进行异或求和,由于原数组中有两个数出现1次(设为a,b),而其他数出现两次,因此由异或运算性质可得,异或求和的结果(设为xorSum)即等于a^b

  • 而两个数异或运算的结果,即代表了这两个数2进制各个数位上的异同,若- xorSum某个bit位上的数值为1(设此bit位为从右往左第一个数值为1的bit),则代表a,b对应bit位上的值不同,可以按照此bit位上的值是否为1,将原始数组中的数分为两类,故a,b必定在不同的两个类别中,且每个类别中的数除了ab以外,其他的数必定出现2次,于是又可以利用异或运算的性质,对两个类别的数直接分别进行求和,两个异或运算之和即直接为两个待查找数ab

PS:

计算某个数x的右边第一个数值为1的bit位对应十进制数公式如下:

  • x & (-x),或x & ((~x)+1)

代码

class Solution {
    public int[] singleNumber(int[] nums) {
        // 排除特殊情况
        if (nums == null || nums.length < 2) return null;
        // 遍历数组,计算异或和
        int xorSum = 0;
        for (int num : nums) {
            xorSum ^= num;
        }
        // 计算异或和值右边第一个数值为1的bit对应的十进制数
        int rightFirstBitOne = xorSum & ((~xorSum) + 1);
        // 按照rightFirstBitOne对应bit位的值,将原始数组进行分组
        // 然后计算其中某一类的异或之和,即为某个待查找数
        int a = 0, b = 0;
        for (int num : nums) {
            // 只需要求出其中一个数a即可
            if ((num & rightFirstBitOne) == 0) {
                a ^= num;
            }
        }
        // xorSum = a^b,故 xorSum^b = a^b^a = b
        b = xorSum ^ a;
        // 返回找到的两个数
        return new int[]{a, b};
    }
}

推广

对于“数组中某2个数出现奇数次,其他数出现偶数次,查找这2个特殊数”的类似问题,都可以使用本题解法进行求和


End~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值