返回
Featured image of post LeetCode 645 - 错误的集合

LeetCode 645 - 错误的集合

表,位运算.

645. Set Mismatch

题目

集合 s 包含从 1n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。

给定一个数组 nums 代表了集合 S 发生错误后的结果。

请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

示例 1:

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

示例 2:

输入:nums = [1,1]
输出:[1,2]

提示:

  • 2 <= nums.length <= 104
  • 1 <= nums[i] <= 104

题解

思路1:哈希表

以数字的值为 key,以数字是否出现过为 value,存入哈希表中。在存储的过程中若发现该 key 对应的 value 已经为 true,则该 key 为重复的数字。存储完成后遍历哈希表,如果某个 key 对应的 value 为 false,则该 key 为丢失的数字。

在[LeetCode 451 - 根据字符出现频率排序]中介绍了使用数组模拟Map的方法,此例中该方法依然适用。

class Solution {
    public int[] findErrorNums(int[] nums) {
        //创建map用于指示数字是否出现过
        boolean[] map = new boolean[nums.length];
        int[] res = new int[2];
        
        //存储的同时查询数字是否为第二次出现
        for(int num : nums){
            if(map[num - 1]){
                res[0] = num;
            }else{
                map[num - 1] = true;
            }
        }
        
        //遍历hash表,查找丢失的数字
        for(int i = 0; i < map.length; i++){
            if(!map[i]){
                res[1] = i + 1;
                break;
            }
        }
        return res;
    }
}

思路2:位运算

如果将 nums1 ~ n 这2n个数字异或,最后的结果 xor 将会是丢失的数字 n1 与重复的数字 n2 的异或。xor 中的每一个值都是 n1n2 的二进制表示中不相同的位。

取其中的一位 bitnums 逐个异或,可以将 nums 分成两组,一组应该存在 n1但它缺失了,另一组 n2 出现了两次。

bit1 ~ n 逐个异或同样可以将其分成两组。将对应的组别异或即可得到 n1n2

最后查找 nums 中出现过的数字为 n2 ,否则其为 n1

class Solution {
    public int[] findErrorNums(int[] nums) {
        int n = nums.length;
        
        //计算 n1 ^ n2
        int xor = 0;
        for (int num : nums) {
            xor ^= num;
        }
        for (int i = 1; i <= n; i++) {
            xor ^= i;
        }
        
        //取 n1 与 n2 二进制表示中一个不相同的位
        int lowbit = xor & (-xor);
        
        //将 nums 分成两组
        int num1 = 0, num2 = 0;
        for (int num : nums) {
            if ((num & lowbit) == 0) {
                num1 ^= num;
            } else {
                num2 ^= num;
            }
        }
        
        //将 1 ~ n 分成两组并异或得到 n1 和 n2
        for (int i = 1; i <= n; i++) {
            if ((i & lowbit) == 0) {
                num1 ^= i;
            } else {
                num2 ^= i;
            }
        }
        
        //辨别 n1 和 n2
        for (int num : nums) {
            if (num == num1) {
                return new int[]{num1, num2};
            }
        }
        return new int[]{num2, num1};
    }
}
comments powered by Disqus