645. 错误的集合——Java

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

给定一个数组 nums 代表了集合 S 发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

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

注意:
给定数组的长度范围是 [2, 10000]。
给定的数组是无序的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/set-mismatch

方法一:暴力解法

最直接的做法就是单独检查 1 到 n 的所有数字。在检查每个数字时都遍历整个 nums 数组,检查当前数字在 nums 中是否出现了两次,或者一次都没有出现。使用 dupmissing 记录重复数字和缺失数字,因此一旦找到这两个数字,就可以提前结束查找过程。

public static int[] findErrorNums(int[] nums) {
    
    
    int dup = -1, missing = -1;
    for (int i = 1; i <= nums.length; i++) {
    
    
        int count = 0;
        for (int j = 0; j < nums.length; j++) {
    
    
            if (nums[j] == i)
                count++;
        }
        if (count == 2)
            dup = i;
        else if (count == 0)
            missing = i;
        if (dup > 0 && missing > 0)
            break;
    }
    return new int[]{
    
    dup, missing};
}

方法二:使用排序

排序 nums 数组后,相等的两个数字将会连续出现。此外,检查相邻的两个数字是否只相差 1 可以找到缺失数字。

public static int[] findErrorNums2(int[] nums) {
    
    
   Arrays.sort(nums);
    int dup = -1, missing = 1;
    for (int i = 1; i < nums.length; i++) {
    
    
        if (nums[i] == nums[i - 1])
            dup = nums[i];
        else if (nums[i] > nums[i - 1] + 1)
            missing = nums[i - 1] + 1;
    }
    return new int[]{
    
    dup, nums[nums.length - 1] != nums.length ? nums.length : missing};
}

方法三:使用 Map

  1. 使用 map 存储 nums 中每个数字的出现次数。存储形式为 (num_i, count_i) 表示数字 num_i 一共出现了count_i 次。当一个元素重复出现时,它的计数就加 1。

  2. 再检查 1n 的每个数字在 map 中出现次数。如果一个数字在 map 中没有出现,它就是缺失数字。如果一个数字的出现了两次,它就是重复数字。

public static int[] findErrorNums3(int[] nums) {
    
    
    Map<Integer, Integer> map = new HashMap();
    int dup = -1, missing = 1;
    for (int n : nums) {
    
    
        if (map.get(n) == null)
            map.put(n, 1);
        else map.put(n, map.get(n) + 1);
    }
    for (int i = 1; i <= nums.length; i++) {
    
    
        if (map.get(i) == null)
            missing = i;
        else if (map.get(i).intValue() == 2)
            dup = i;
    }
    return new int[]{
    
    dup, missing};
}

方法四:使用额外数组

如果使用 map 存储每个数字出现的次数,每个数字都需要两个变量分别存储数字本身和出现次数,因此存储 n 个数字和出现次数需要 2n 的空间。如果使用数组 arrarr 代替 map,可以将空间减少到 n。

在数组 arr 中,索引代表数字,arr 存储每个数字出现的次数。例如 arr[i] 存储数字 i 出现的次数。

public int[] findErrorNums4(int[] nums) {
    
    
    int[] arr = new int[nums.length + 1];
    int dup = -1, missing = 1;
    for (int i = 0; i < nums.length; i++) {
    
    
        arr[nums[i]] += 1;
    }
    for (int i = 1; i < arr.length; i++) {
    
    
        if (arr[i] == 0)
            missing = i;
        else if (arr[i] == 2)
            dup = i;
    }
    return new int[]{
    
    dup, missing};
}

方法五:使用额外空间

已知 nums 中所有数字都是正数,且处于 1n 之间。遍历 nums 中的所有数字,根据数字 i 找到 nums[∣i∣],如果是第一次访问 nums[∣i∣],将它反转为负数。如果是第二次访问,则会发现它已经是负数。因此,可以根据访问一个数字时它是否为负数找出重复数字。

完成上述操作后,所有出现过的数字对应索引处的数字都是负数,只有缺失数字 j 对应的索引处仍然是正数。

public static int[] findErrorNums5(int[] nums) {
    
    
    int dup = -1, missing = 1;
    for (int n: nums) {
    
    
        if (nums[Math.abs(n) - 1] < 0)
            dup = Math.abs(n);
        else
            nums[Math.abs(n) - 1] *= -1;
    }
    for (int i = 1; i < nums.length; i++) {
    
    
        if (nums[i] > 0)
            missing = i + 1;
    }
    return new int[]{
    
    dup, missing};
}

猜你喜欢

转载自blog.csdn.net/m0_46390568/article/details/107722777
今日推荐