41. First Missing Positive

题目描述(困难难度)

在这里插入图片描述
题目描述:给一串数字,找出缺失的最小正数。限制了时间复杂度为 O(n),空间复杂度为 O(1)。

解法一 交换

如果没限制空间复杂度,我们可以这样想。用一个等大的数组去顺序保存这些数字。

比如说,数组 nums [ 3 4 -1 1 8],它的大小是 5。然后再创建一个等大的数组 a,初始化为 [ - 1,- 1,- 1,- 1,-1] 。然后我们遍历 nums,把数字分别存到对应的位置。1 就存到数组 a 的第 1 个位置(a [ 0 ]),2 就存到数组 a 的第 2 个位置(a [ 1 ]),3 就存到数组 a 的第 3 个位置(a [ 2 ])…

nums [ 0 ] 等于 3,更新 a [ - 1,- 1,3,- 1,-1] 。

nums [ 1 ] 等于 4,更新 a [ - 1,- 1,3,4,-1 ] 。

nums [ 2 ] 等于 - 1,不是正数,忽略。

nums [ 3 ] 等于 1,更新 a [ 1,- 1,3,4,-1 ] 。

nums [ 4 ] 等于 8,我们的 a 数组只能存 1 到 5,所以同样忽略。

最后,我们只需要遍历 a 数组,遇到第一次 a [ i ] != i + 1,就说明缺失了 i + 1。因为我们的 a 数组每个位置都存着比下标大 1 的数。

当然,上边都是基于有一个额外空间讲的。如果没有额外空间,怎么办呢?

我们直接把原数组当成 a 数组去用。 这样的话,会出现的问题就是之前的数就会被覆盖掉。覆盖之前我们把它放回到当前数字的位置, 换句话说就是交换一下位置。然后把交换回来的数字放到应该在的位置,又交换回来的新数字继续判断,直到交换回来的数字小于 0,或者大于了数组的大小,或者它就是当前位置放的数字了。接着遍历 nums 的下一个数。具体看一下。

nums = [ 3 4 -1 1 8 ]

nums [ 0 ] 等于 3,把 3 放到第 3 个位置,并且把之前第 3 个位置的 -1 放回来,更新 nums [ -1, 4, 3, 1, 8 ]。

然后继续判断交换回来的数字,nums [ 0 ] 等于 -1,不是正数,忽略。

nums [ 1 ] 等于 4,把 4 放到第 4 个位置,并且把之前第 4个位置的 1 放回来,更新 nums [ -1, 1, 3, 4, 8 ]。

然后继续判断交换回来的数字,nums [ 1 ] 等于 1,把 1 放到第 1 个位置,并且把之前第 1 个位置的 -1 放回来,更新 nums [ 1, -1, 3, 4, 8 ]。

然后继续判断交换回来的数字,nums [ 1 ] 等于 -1,不是正数,忽略。

nums [ 2 ] 等于 3,刚好在第 3 个位置,不用管。

nums [ 3 ] 等于 4,刚好在第 4 个位置,不用管。

nums [ 4 ] 等于 8,我们的 nums 数组只能存 1 到 5,所以同样忽略。

最后,我们只需要遍历 nums 数组,遇到第一次 nums [ i ] != i + 1,就说明缺失了 i + 1。因为我们的 nums 数组每个位置都存着比下标大 1 的数。

看下代码吧,一个 for 循环,里边再 while 循环。

Java

public class First_Missing_Positive {
	public static int firstMissingPositive(int[] nums) {
	    int n = nums.length;
	    //遍历每个数字
	    for (int i = 0; i < n; i++) {
	        //判断交换回来的数字
	        while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {
	            //第 nums[i] 个位置的下标是 nums[i] - 1
	            swap(nums, i, nums[i] - 1);
	        }
	    }
	    //找出第一个 nums[i] != i + 1 的位置
	    for (int i = 0; i < n; i++) {
	        if (nums[i] != i + 1) {
	            return i + 1;
	        }
	    }
	    //如果之前的数都满足就返回 n + 1
	    return n + 1;
	}
	private static void swap(int[] nums, int i, int j) {
	    int temp = nums[i];
	    nums[i] = nums[j];
	    nums[j] = temp;
	}
	public static void main(String args[]) {
		int[]nums= {3,4,-1,1};
		int ans=firstMissingPositive(nums);
		System.out.println(ans);
	}
}

时间复杂度:for 循环里边套了个 while 循环,如果粗略的讲,那时间复杂度就是 O(n²)了。我们再从算法的逻辑上分析一下。因为每交换一次,就有一个数字放到了应该在的位置,只有 n 个数字,所以 while 里边的交换函数,最多执行 n 次。所以时间复杂度更精确的说,应该是 O(n)。

空间复杂度:O(1)。

Python

def firstMissingPositive(nums):
    n=len(nums)
    #遍历每个数字
    for i in range(0,n):
        #判断交换回来的数字
        while (nums[i] > 0 and nums[i] <= n and nums[i] != nums[nums[i] - 1]):
            #第 nums[i] 个位置的下标是 nums[i] - 1
            swap(nums, i, nums[i] - 1)

    #找出第一个 nums[i] != i + 1 的位置
    for i in range(0,n):
        if (nums[i] != i + 1):
            return i + 1;
            
    #如果之前的数都满足就返回 n + 1
    return n + 1;

def swap(nums, i, j):
    temp = nums[i]
    nums[i] = nums[j]
    nums[j] = temp

Python

思想也是非常简单粗暴。由于题目中需要找到的最小正整数。
首先利用sorted函数将数组升序排列,其次将原数组中的正整数生成新的数组,最后通过各种判断条件编写具体函数功能。

class Solution(object):
    def firstMissingPositive(self, nums):
        nums = sorted(nums)
        nums=[x for x in nums if x>0]
        if (len(nums)>1 and nums[0]!=1) or len(nums)==0 or nums[0]>1:
            return 1
        i=0
        j=1
        while(j<len(nums)):
            if(nums[j]-nums[i]==1):
                i+=1
                j+=1
            elif (nums[j] - nums[i]) != 1 and nums[i]!=nums[j]:
                return nums[i] + 1
            elif (nums[i]==nums[j]):
                i+=1
                j+=1
        return nums[j-1]+1      

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

安替-AnTi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值