41.缺失的第一个正数 python

题目

题目描述

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

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

示例 1:

输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。

示例 2:

输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。

示例 3:

输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。

提示:

1 <= nums.length <= 105
-2^31 <= nums[i] <= 2^31 - 1

题解

这个问题可以通过一种巧妙的方法在 O(n) 时间复杂度和常数级别的额外空间内解决。核心思想是利用数组的索引作为哈希键,将每个正整数放置到它应该在的位置上。具体来说,就是让数值 1 放置在索引 0 处,数值 2 放置在索引 1 处,依此类推。

解决思路

  1. 遍历数组:首先遍历数组,将每个位于范围 [1, n] 内的数字放到它对应的索引位置上(即数值 x 应该放在索引 x-1)。如果一个数字已经在正确的位置上或者不在有效范围内(小于等于 0 或大于 n),则跳过这个数字。

  2. 第二次遍历:再次遍历数组,找到第一个不匹配其索引 + 1 的位置,这个位置的索引 + 1 就是缺失的第一个正整数。如果所有位置都匹配,则说明数组包含了从 1n 的所有数字,因此答案是 n+1

Python 实现代码

以下是按照上述思路实现的 Python 代码:

def firstMissingPositive(nums):
    if not nums:
        return 1
    
    n = len(nums)
    
    # 第一步:把不在 [1, n] 范围内的数替换为 n+1(或任何大于 n 的数)
    for i in range(n):
        if nums[i] <= 0 or nums[i] > n:
            nums[i] = n + 1
    
    # 第二步:使用索引和数值之间的关系来标记哪些数字出现过
    for i in range(n):
        num = abs(nums[i])
        if 1 <= num <= n:
            nums[num - 1] = -abs(nums[num - 1])
    
    # 第三步:找到第一个正数的索引,这就是缺失的第一个正整数
    for i in range(n):
        if nums[i] > 0:
            return i + 1
    
    # 如果所有索引处都是负数,则意味着 [1, n] 都存在,所以返回 n+1
    return n + 1

代码解释

  • 第一步:将所有不在 [1, n] 范围内的数字替换成 n+1,因为我们只关心 [1, n] 范围内的数字。

  • 第二步:遍历数组,对于每一个在 [1, n] 范围内的数字 num,我们将它对应的索引 num-1 处的值变为负数,以此来标记这个数字已经出现过。注意这里我们使用了绝对值函数 abs() 来确保即使某个位置已经被标记为负数,我们仍然可以正确地访问原始值。

  • 第三步:最后再遍历一次数组,寻找第一个仍然是正数的位置,这表示对应的正整数没有出现在数组中。如果整个数组都被标记成了负数,则说明 [1, n] 中的所有数字都在数组中出现了,因此返回 n+1

这种方法不仅满足了时间复杂度 O(n) 和常数级别额外空间的要求,而且非常直观易懂。

提交结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gxls2024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值