微信公众号:路人zhang
网站救助计划

1.为阅读体验,本站无任何广告,也无任何盈利方法,站长一直在用爱发电,现濒临倒闭,希望有能力的同学能帮忙分担服务器成本


2.捐助10元及以上同学,可添加站长微信lurenzhang888,备注捐助网站倒闭后可联系站长领取本站pdf内容


3.若网站能存活下来,后续将会持续更新内容

当前位置: 算法 > 剑指offer > 剑指offer 56-1. 数组中数字出现的次数

题目描述

一个整型数组 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 <= nums.length <= 10000

题解

(位运算,异或) O(n)

首先我们知道求数组中只出现一次的一个数字的求法,因为除了这个数其他数都出现了两次,所以将所有数异或起来的结果就是答案。

这道题目要求的是只出现一次的两个数字,我们需要想办法把它拆解成第一类问题

假设两个数字为 x、y

  1. 先将所有数异或起来的结果记为 sum = x ^ y,因为其他数字都出现两次,它们异或的结果是 0
  2. 由于 x != y 则 x 和 y 不全为 0,所以 sum 必不为 0,那么 sum 的二进制表示中肯定有 1,且对于为 1 位,x 和 y 必然其中一个为 1,另一个为 0,否则异或的结果当前位不可能为 1,按照 sum 的二进制表示中最后一个 1(假设是第 k 位) 所有数划分为两个集合,一个集合中第 k 位全为 1,另一个集合中第 k 位全为 0,且 x 和 y 不在同一个集合
  3. 此时问题就转换成了求两个「数组中只出现一次的一个数字」,对两个集合分别异或起来,得到的就是 x 和 y

优化:只求一个集合的异或结果可以得到一个数 first (= x / y),而已知 sum = x ^ y,则 first ^ sum 就是另一个数

时间复杂度

考虑最长时间就是遍历数组所花费的时间,时间复杂度为 O(n)。

空间复杂度

O(1)

C++ 代码

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int sum = 0;
        for (auto x : nums) sum ^= x;
        int t = sum & -sum; // t 表示 sum 的最后一个表示的二进制数,比如 100100,结果就是 100
        int first = 0;
        for (auto x : nums)
            if (x & t) // 如果是 1,则分到和 first 一组
                first ^= x;
        return {first, sum ^ first};
    }
};

Java 代码

class Solution {
    public int[] singleNumbers(int[] nums) {
        int sum = 0;
        for (int x : nums) sum ^= x;
        int t = sum & -sum; // t 表示 sum 的最后一个表示的二进制数,比如 100100,结果就是 100
        int first = 0;
        for (int x : nums) {
            if ((x & t) != 0) { // 如果是 1,则分到和 first 一组
                first ^= x;
            }
        }
        return new int[]{first, sum ^ first};
    }
}

Python 代码

class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        xor_sum = 0
        for x in nums:
            xor_sum ^= x
        t = xor_sum & -xor_sum  # t 表示 xor_sum 的最后一个表示的二进制数,比如 100100,结果就是 100
        first = 0
        for x in nums:
            if x & t:  # 如果是 1,则分到和 first 一组
                first ^= x
        return [first, xor_sum ^ first]

本文由读者提供Github地址:https://github.com/tonngw


点击面试手册,获取本站面试手册PDF完整版