力扣第四十一题-缺失的第一个正数

426 阅读2分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

前言

力扣第四十一题 缺失的第一个正数 如下所示:

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

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

示例 2:

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

示例 3:

输入: nums = [7,8,9,11,12]
输出: 1

一、思路

这一题比较难的地方就是需要:实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案

如果没有 常数级别 的额外空间的要求,我们可以使用哈希表来快速找到 缺失的第一个正数

这一题有一个非常重要的信息:

  • 长度为 N 的数组中,缺失的最小正数 只会在在 [1, N+1]

我们可以把他想象成 占座,比如数字 1 的位置为 :

  1. 排除负数的干扰:将所有的负数置为 N + 1,放到数组外,排除干扰
  2. 正数占位:将正数数值对应的下标上面的数,置为 nums[val] = -|nums[val]|。例如:正数 5 对应的下标为 4,并将 nums[4] = -Math.abs(nums[4])
  3. 遍历:找到第一个正数,返回 i + 1。如果没有则返回 N + 1

举个例子

此处以 nums=[2, 5, 3, 4, -1, 7, 1]作为例子

1. 排除负数干扰

将负数置为 N + 1,结果如下所示:

image.png

2. 正数占位

正数占位后如下所示:

image.png

3. 遍历

很明显遍历正数为下标为 5 的正数 7

image.png

直接返回该下标 + 1 值为 6 即可

二、实现

实现代码

实现代码与思路中保持一致

public int firstMissingPositive(int[] nums) {
    int n = nums.length;
    // 排除负数干扰
    for (int i = 0; i < n; ++i) {
        if (nums[i] <= 0) {
            nums[i] = n + 1;
        }
    }
    // 正数占位置
    for (int i = 0; i < n; ++i) {
        int val = Math.abs(nums[i]);
        if (val <= n) {
            nums[val - 1] = -Math.abs(nums[val - 1]);
        }
    }
    // 遍历
    for (int i = 0; i < n; ++i) {
        if (nums[i] > 0) {
            return i + 1;
        }
    }
    return n + 1;
}

测试代码

public static void main(String[] args) {
    int[] nums= {2, 5, 3, 4, -1, 7, 1};
    new Number41().firstMissingPositive(nums);
}

结果

image.png

三、总结

击败率不是很理想,有待改进!

感谢看到最后,非常荣幸能够帮助到你~♥