题解报告LeetCode#41:缺失的第一个正数

题意:LeetCode#41:缺失的第一个正数

思路:

  • 本题的难点在:只能使用常数级别的额外空间,在这个限制下本题的思路有一个非正式的名称:原地哈希。
  • 由于题目要求我们「只能使用常数级别的空间」,而要找的数一定在 [1, N + 1] 左闭右闭(这里 N 是数组的长度)这个区间里。因此,我们可以就把原始的数组当做哈希表来使用。事实上,哈希表其实本身也是一个数组;
  • 我们要找的数就在 [1, N + 1] 里,最后 N + 1 这个元素我们不用找。因为在前面的 N 个元素都找不到的情况下,我们才返回 N + 1
  • 那么,我们可以采取这样的思路:就把 1 这个数放到下标为 0 的位置, 2 这个数放到下标为 1 的位置,按照这种思路整理一遍数组。然后我们再遍历一次数组,第 1 个遇到的它的值不等于下标的那个数,就是我们要找的缺失的第一个正数。
  • 这个思想就相当于我们自己编写哈希函数,这个哈希函数的规则特别简单,那就是数值为 i 的数映射到下标为 i - 1 的位置。

其实这里你最主要就是去了解题意中[7,8,9,11,12]中这个例子,这个例子在下面代码中的while一次都没覆盖到,再之后的for判断返回值当然返回 1 咯。

代码:

  1. class Solution {
  2. public int firstMissingPositive(int[] nums) {
  3. int len = nums.length;
  4. for (int i = 0; i < len; i ++) {
  5. while (nums[i] >= 1 && nums[i] <= len && nums[nums[i] - 1] != nums[i]) {
  6. // 满足在指定范围内、并且没有放在正确的位置上,才交换
  7. // 例如:数值 3 应该放在索引 2 的位置上
  8. swap(nums, nums[i] - 1, i);
  9. }
  10. }
  11. for (int i = 0; i < nums.length; i++) {
  12. if (nums[i] != i + 1) {
  13. return i + 1;
  14. }
  15. }
  16. // 都正确则返回数组长度 + 1
  17. return len + 1;
  18. }
  19. private void swap(int[] nums, int index1, int index2) {
  20. int temp = nums[index1];
  21. nums[index1] = nums[index2];
  22. nums[index2] = temp;
  23. }
  24. }

题解报告LeetCode#442:数组中的重复数据

题意:LeetCode#442:数组中的重复数据

思路:

  1. 自己的解法和威哥的解法其实大同小异,都用到了原地哈希的思想,也就是将元素放到它本来应该身处的位置上去。

代码:

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res = new ArrayList<>();

        int len = nums.length;
        for (int i = 0; i < len; i++) {
            while (nums[i] > 0 && nums[i] - 1 != i) {
                if (nums[nums[i] - 1] == nums[i]) {
                    res.add(nums[i]);
                    // 将重复的元素替换为负数做标记
                    nums[i] = -1;
                    break;
                }
                swap(nums, nums[i] - 1, i);
            }
        }   

        return res;
    }

    private void swap (int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

他山之玉:

public class Solution {

    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res = new ArrayList<>();
        int len = nums.length;

        for (int i = 0; i < len; i++) {
            while (nums[nums[i] - 1] != nums[i]) {
                swap(nums, i, nums[i] - 1);
            }
        }
        for (int i = 0; i < len; i++) {
            if (nums[i] - 1 != i) {
                res.add(nums[i]);
            }
        }

        return res;
    }

    private void swap (int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

题解报告LeetCode#448:找到数组中消失的数字

题意:LeetCode#448:找到数组中消失的数字

思路:原地哈希

代码:

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> res = new ArrayList<>();

        int len = nums.length;
        for (int i = 0; i < len; i++) {
            // 对应位置上的值不是它应该有的值时,进入一趟
            while (nums[nums[i] - 1] != nums[i]) {
                swap(nums, nums[i] - 1, i);
            }
        }

        for (int i = 0; i < len; i++) {
            if (nums[i] != i + 1) {
                res.add(i + 1);
            }
        }

        return res;
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}