LeetCode41.缺失的第一个正数

1. 题目大意

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

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

2. 思路分析

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

根据示例,对于一个长度为 N 的数组,其中没有出现的最小正整数只能在[1, N+1]中。这是因为如果[1, N]都出现了,那么答案是N+1,否则答案是 [1, N]中没有出现的最小正整数。

题目又要求我们不能使用额外空间,所以我们直接对原数组进行操作。因为我们只需要关注数组中[1, N]之间的数,所以可以把值i, 置换到数组对应下标的位置,得到nums[i-1] = i。这里忽略<=0 & >N的值。

上面提到过程中,本质上涉及元组两个元素的交换,如果nums[i-1] != i则需要反复执行上面的流程。示例1变换流程:

arrayindex说明
[3, 4, -1, 1]0
[-1, 4, 3, 1]0首先交换3和-1,虽然nums[0]!=1但是出现负值接着往前走
[-1, 1, 3, 4]1置换1和4
[1, -1, 3, 4]1因为nums[1] != 2, 所以继续置换,使得nums[0] = 1
[1, -1, 3, 4]2nums[2] = 3,继续
[1, -1, 3, 4]2nums[3] = 4,结束

最后我们只需要查找置换后数组中nums[i] != i-1的情况,如果数组中都没有出现上述情况则直接返回N+1

3. 代码示例

Java版本

class Solution {
    public int firstMissingPositive(int[] nums) {
        for(int i=0; i<nums.length; i++){
            while(nums[i] > 0 && nums[i] <= nums.length && nums[i] != i+1 && 
            		nums[i] != nums[nums[i]-1]){ 
           		// nums[i] != nums[nums[i]-1]:避免数组中有值重复的情况
                int n = nums[i]-1;
                int tmp = nums[n];
                nums[n] = nums[i];
                nums[i] = tmp;
            }
        }
        System.out.println(Arrays.toString(nums));
        for(int i=0; i<nums.length; i++){
            if(nums[i] != (i+1) || nums[i] <= 0)
                return i+1;
        }
        return nums.length+1;
    }
}

Python版本

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        l = len(nums)
        if l == 0:
            return 1
        for i in range(l):
            while(1 <= nums[i] <= l and nums[i] != i+1 and nums[i] != nums[nums[i] - 1]):
                # nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
        for i in range(l):
            if nums[i] != i+1:
                return i+1
        return l+1

在上述的while循环中nums[i] != nums[nums[i]-1]是为了避免数组中有值重复的情况,如果不加出处理就会一直被置换,陷入死循环。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值