【LeetCode】解题41:First Missing Positive

这篇博客介绍了LeetCode第41题的解决方案,使用哈希表策略在O(n)时间和常数空间复杂度内找到数组中最小的缺失正整数。解题过程中,通过修改数组元素的符号来实现原地操作,避免额外空间。内容涵盖解题思路、难点解析和Java实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem 41: First Missing Positive [Hard]

Given an unsorted integer array, find the smallest missing positive integer.

Example 1:

Input: [1,2,0]
Output: 3

Example 2:

Input: [3,4,-1,1]
Output: 2

Example 3:

Input: [7,8,9,11,12]
Output: 1

Note:

Your algorithm should run in O(n) time and uses constant extra space.

来源:LeetCode

解题思路

基本思想为哈希表,将数组的值与坐标联系起来,第一遍循环时根据值nums[i]用一定规律改变该坐标指向的值nums[nums[i]],第二遍循环时根据上述规律找出未被改变的坐标,即为第一个缺失的正数。

难点

  1. 由于题目中要求只能使用常数级别的额外空间,因此不能创建新数组newnums[N],使用newnums[nums[i]]=1的方法记录nums中的值,只能使用in-place的方法在原数组nums上修改,同时不能改变原本的信息。
    【解决方法】: 通过改变nums[nums[i]]的符号,来记录数组中的值nums[i]
  2. nums[i]的值有可能不在数组的坐标范围内。
    【解决方法】: 假设数组长度为N,则第一个缺失的正数不可能大于N+1,因此数组中小于等于0和大于N的值都可以忽略,只关注[1, N]范围内的数。

具体思路:

  • 首先遍历数组,记录数组中是否含有1,并将非正数和大于N的值改为1。假如原本不含1,则1就是第一个缺失的正数,可以直接返回。
  • 第二次遍历数组,此时数组中的值的范围应该是[1, N],遍历至nums[i]时,取其绝对值作为坐标pos,将nums[pos-1]的值变为负数,若已经是负数则保持负数,这一步将数组中的值[1, N]映射到相应坐标[0, N-1]上。
    例如:nums[i] = 5,则将nums[4]变为-|nums[4]|。
  • 第三次遍历数组,检查nums[i]的符号,若为正数,说明数组中没有出现值i+1,此时直接返回i+1
  • 如果nums[i]都为负数,说明整数1~N都出现过,则应返回N+1。

整个算法一共遍历了三次数组,时间复杂度为O(n),空间复杂度为O(1)。

要点:哈希表in-place

Solution (Java)

class Solution {
    public int firstMissingPositive(int[] nums) {
        int N = nums.length;
        int min = 0;
        for(int i = 0; i < N; i++){
            if(nums[i] == 1){
                min = 1;
            }
            else if(nums[i] < 1 || nums[i] > N){
                nums[i] = 1;
            }
        }
        if(min == 0) return 1;

        int pos;
        for(int i = 0; i < N; i++){
            pos = Math.abs(nums[i]);
            nums[pos-1] = - Math.abs(nums[pos-1]);
        }
        for(int i = 0; i < N; i++){
            if(nums[i] > 0) return i+1;
        }
        return N+1;
    }
}

修改过程

  • 一般的哈希表思路需要另外创建一个长度为N的数组,不符合只能使用常数级别空间的题意,因此需要用in-place的想法,利用符号达到哈希表效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值