【小白用python刷Leetcode】41.缺失的第一个正数

41.缺失的第一个正数

题目描述

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

示例:

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

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

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

提示:你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
(确定这是提示,不是进阶要求???好吧我是真的小白)
 

我的思路(小白思路)

先将数组排序,然后定义一个key。key的初值设为1,利用二分查找在排序后的数组中找key。如果找到了,则key = key+1,并对比key和数组中下一个数是否相等,直到不等的时候或者遍历完剩余数组,则当前key就是第一个缺失的正数;如果没找到直接返回key,就是缺失的。
时间复杂度太高了,可是居然跑过了,神奇。

def firstMissingPositive(self, nums: List[int]) -> int:
        nums = sorted(set(nums))
        key = 1
        def find(nums,key): #二分查找
            left = 0
            right = len(nums)-1
            while left <= right:
                mid = (left+right)//2
                if nums[mid] == key:
                    return mid
                elif nums[mid] < key:
                    left = mid+1
                else:
                    right = mid-1
            return -1
        pos = find(nums,key)
        if pos != -1:
            nums = nums[pos+1:]
            key += 1
            for x in nums:
                if x == key:
                    key += 1
                else:
                    return key

        else:
            return 1
        return key

官方思路(感觉是有点牛逼的)

官方思路里要用到类哈希表的思路,而我又是一个小白,并不清楚什么是哈希表。官方题解没说到哈希表需要排序,不知道这是不是哈希表的特殊性质,看来要补充一下关于哈希表的知识。

哈希表:可以支持快速查找的数据结构;给定一个元素,我们可以在 O(1) 的时间查找该元素是否在哈希表中。

具体的思路妙在将数组改成类哈希表的样子。首先需要明确:如果给定的数组长度为n的话,那么我们要找的数一定在[1, n+1]这个区间内。原因:左边界为1闭区间,因为是正整数;右边界为n+1闭区间,考虑最坏情况,即数组中的数都是连续的正整数,且从1开始,则我们要找的数就是n+1,因为是最坏情况,所以这就是要找的数的最大可能值。其他情况,比如非连续的正整数数组,或者连续但是并不从1开始,要找的值一定在[1, n+1]中。

具体算法流程如下:
 1.     先遍历整个数组,将所有非整数都修改为n+1
 2.    遍历数组,每次遍历取当前值x的绝对值|x|,如果|x|落在[1, n]内,则将数组内|x|-1位置上的数标记为负(-1是因为数组的位置从0开始记),如果已为负数则不再重复标记。这里要用绝对值而不是取原值的意义在于,遍历中每一次取的数有可能已经被标记过了,所以用|x|。
 3.     最后再看修改后的数组,第一个正数出现的位置pos,pos+1就是我们要找的那个正整数。
 4.     如果所有数都被标记,则表明这个数组是连续且从1开始的,则输出n+1。

思路理解:我们将数组内所有的|x|作为位置,并将相应位置上(|x|-1)的数标记为负,这种做法相当于将当前数组进行了一种排序,即这个数组如果进行排序,且数组的最小值如果为1的话(即最坏情况,上文提到的整个数组连续但乱序且从1开始),当前所取的值(满足在[1, n])应该在的位置,我们其实是将这个位置标记为负。那么如果有位置没有被标记,则这个位置在排序后所存在的数自然就是缺失的那个。当然,如果全都被标记了,那么就是不缺失,取n+1就好。(只是个人理解,不一定对,欢迎指正)
时间复杂度:O(n)    空间复杂度:O(1)

def firstMissingPositive(self, nums: List[int]) -> int:
        n = len(nums)
        for i in range(n):
            if nums[i] <= 0:
                nums[i] = n+1
        for x in nums:
            if abs(x) >=1 and abs(x) <= n and nums[abs(x)-1] > 0:
                nums[abs(x)-1] = -nums[abs(x)-1]
        for i in range(n):
            if nums[i] > 0:
                return i+1
        return n+1

官方题解的思路二和上面的思路大同小异,只不过将打标记变为了直接换位置,可能更直观吧。简单来说就是位置变换后数组内位置i上的数字应该为i+1;若不是,说明缺失。感觉比以上的思路要稍麻烦一点点,毕竟换位置不像打标记那么简单。

以上就是我,一个正儿八经的小白(大神们通过看代码应该也感觉出来了),对这道题的理解,欢迎诸位指正讨论,感谢阅读。

原题链接:
https://leetcode-cn.com/problems/first-missing-positive/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值