缺失的第一个正整数:给定一个未排序的整数数组,找出其中未出现的最小正整数

75 篇文章 0 订阅

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


(本文获得CSDN质量评分【90】)

【学习的细节是欢悦的历程】


  自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
            —— 华罗庚


等风来,不如追风去……


给定一个未排序的整数数组
缺失的第一个正整数
(找出其中未出现的最小正整数)


本文质量分:

90
本文地址: https://blog.csdn.net/m0_57158496/article/details/129635313

CSDN质量分查询入口:http://www.csdn.net/qc


目 录


◆缺失的第一个正数


1、题目描述

  给你一个未排序的整数数组nums,请你找出其中没有出现的最小的正整数。请你实现时间复杂度为 O(n) 并且只使用常1数级别额外空间的解决方案。

样例 1:

输入:
nums = [1, 2, 0]

输出:
3

样例2:

输入:
nums = [3, 4, -1, 1]

输出:
2

样例 3:

输入:
nums = [7, 8, 9, 11, 12]

输出:
1

提示:

  • 1 <= nums.length <= 5 * 105
  • -231 <= nums[i] <= 231 - 1


回页目录

2、大佬题解


   从大佬的博文中剪来的题解代码,其中while一段以我目前水准读不明白。

2.1 CV的“原码”


class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        n = len(nums)
        for i in range(n):
            while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
                input(nums) 
                nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]

        for i in range(n):
            if nums[i] != i + 1:
                return i + 1
        return n + 1

以上这段代码的逻辑:
  “好在题目没说参数空间不可以修改,不说就是默认,我们就用参数的空间。我们把在范围内的正数放在对应的位置,处理完一遍数组后,第二次遍历数组,对应位置数字不对的就是缺失的正数。



def firstMissingPositive(self, nums: List[int]) -> int:
    pass

  这函数形参的定义语法,我的两个Python环境都“死活”不认。😣
在这里插入图片描述
在这里插入图片描述
  函数定义原语句,修改成了我Python喜欢的样子,才成功跑起来了。


    def firstMissingPositive(self, nums) -> int:
        pass

2.2 读不明白算法代码


  以我目前的Python学识,读不明白那while那一段代码,加了两个print()“显形”,才晓得是起“排序”作用。😝


代码


    def firstMissingPositive(self, nums) -> int:
        n = len(nums)
        for i in range(n):
            print(nums) # 添加的调试用语句。
            while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
                nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
        print(nums) # 添加的调试用语句。


效果截屏
在这里插入图片描述

2.3 弄懂代码

  经过仔细拆解,终于读懂大佬算法代码。

  原来大佬说的“……把在范围内的正数放在对应的位置,处理完一遍数组后……”,意思是遍历一遍数组,把<=数组长度len(nums)的正整数放在其对应的正确位置(设定数组第一个位置放1),依次处理每个正整数。nums[nums[i] - 1] != nums[i]的意义是遍历到的数组“元素自己的值减1不等于它自己的下标”,即nums[i] - 1 != i。这个条件表达式,可以换为后面一句的写法,“判定值减1是否等于它的下标”。


class Solution:
    #def firstMissingPositive(self, nums: List[int]) -> int:
    def firstMissingPositive(self, nums) -> int:
        n = len(nums)
        for i in range(n):
            print('\n遍历位置:i =', i)
            #while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]: # 原作者写法。
            while 0 < nums[i] <= n and nums[i] - 1 != i:
                print(nums)
                nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1]        
        print(f"\n{nums}\n") 
        for i in range(n):
            if nums[i] != i + 1:
                return i + 1
        return n + 1

  不得不说,读懂佬的算法代码,才真正体会到算法的精巧,让人叹服。


样例实操:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  样例3给出的整数都大于其长度5,不作处理。第一个位置不是1,1即是未出现过的最小正整数。


回页目录

3、我的理解


  题目要求从给定数组中找出未出现过的最小正整数,正整数即是不含“0”的自然数,那么从1开始升序查找判定就好。首先对数组升序排序(题目描述中没说明不可以用轮子,我认为调用或者自码排序代码,都是可行的),然后截取正数部分比对判定,找出未出现过最小正整数。

3.1 借轮“出海”


  借用list.sort()排正序,enumerate()枚举同时遍历下标和数组元素本身。

代码


def findmin(nums):
    ''' 找出数列中未出现的最小正数 '''
    nums = [i for i in nums if i > 0] # 列表解析出给定数组的自然数部分。
    nums.sort() # 排正序。list.sort()默认正序。

    for k,i in enumerate(nums):
        if nums[k+1] - 1 != i:
            return i + 1
    
    return i + 1

3.3 衍生解法


  弄明白前面的算法代码,手痒痒的,用算法思想借助list的remove、append帮助,用for一次遍历,if语句改写了前面的算法代码中for下嵌套的while循环体。
  代码虽然臃肿了些,但还是达到了解题的目的,就是处理稍微慢了一些。


def findmin(nums):
    ''' 依佬“变种”,找出数列中未出现的最小正数 '''
    n = len(nums)

    for i in nums[:]:
        k = nums.index(i)

        if i - 1 != k and 0 < i <= n:
            nums[i-1], nums[k] = i, nums[i-1]
        elif i <= 0 or i > n:
            nums.remove(i)
            nums.append(i)
         
    print(f"\n处理后数组:\n{nums}")
    
    for i in nums:

        if i-1 != nums.index(i):
            return nums.index(i) + 1

    return i + 1

在这里插入图片描述


3.2 用“in”解题


  用Python成员判定指令in来解题,无须对nums输入数组排序。用msx(nums)取出最大整数,遍历1~最大整数的整数列表,依次判定在不在数组num中,当i in nums的值为False时,即找到缺失的最小整数。这个算法只需遍历“最小缺失值”次 (从1~n依次遍历),我觉得是“易读易懂”的轻便算法。


代码


def findmin(nums):
    ''' 找出数列中未出现的最小正数 '''

    for i in range(1, max(nums)):
        if i not in nums: # not False即是True。
            return i

     return i+1

  一层for,一个if…elif…,在Python成员判定关键字“in”的助力下完成对输入的处理、输出。
  


回页目录

4、完整源码

(源码较长,点此跳过源码)

#!/sur/bin/nve python
# coding: utf-8


def findmin(nums):
    ''' “list.sort()”找出数列中未出现的最小正数 '''
    nums = [i for i in nums if i > 0] # 列表解析出给定数组的自然数部分。
    nums.sort() # 排正序。list.sort()默认正序。

    for k,i in enumerate(nums):
        if nums[k] != i:
            return i + 1
    
    return i + 1


def findmin4(nums):
    ''' 依佬“变种”,找出数列中未出现的最小正数 '''
    n = len(nums)

    for i in nums[:]:
        k = nums.index(i)

        if i - 1 != k and 0 < i <= n:
            nums[i-1], nums[k] = i, nums[i-1]
        elif i <= 0 or i > n:
            nums.remove(i)
            nums.append(i)
         
    print(f"\n处理后数组:\n{nums}")
    
    for i in nums:

        if i-1 != nums.index(i):
            return nums.index(i) + 1

    return i + 1


def findmin5(nums):
    ''' “in”,找出数列中未出现的最小正数 '''
    for i in range(1, max(nums)):
        if i not in nums: # not False即是True。
            return i


class Solution:
    #def firstMissingPositive(self, nums: List[int]) -> int:
    def firstMissingPositive(self, nums) -> int:
        n = len(nums)
        for i in range(n):
            print('\n遍历位置:i =', i)
            #while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
            while 0 < nums[i] <= n and nums[i] - 1 != i:
                print(nums)
                nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1]        
        print(f"\n{nums}\n") 
        for i in range(n):
            if nums[i] != i + 1:
                return i + 1
        return n + 1


if __name__ == '__main__':
    from time import time
    result = Solution()
    nums = [1, 2, 0]
    nums = [3, 4, -1, 1]
    nums = [7, 8, 9, 11, 12]
    nums = [8, -1, 5, 4, 1, 3, 2]
    nums = [4, 3, 2, 1]

    print('\n输入:')
    print(*nums)
    print()

    start_s = time() # 获取当前时间秒。

    #print(f"\n输出:\n{result.firstMissingPositive(nums)},程序用时{time() - start_s:.8f}秒。")
    print(f"\nmy输出:\n{findmin(nums)},程序用时{time() - start_s:.8f}秒。")

    

回页首

__上一篇:__ 圆桌(CSDN周赛第30期第四题解析)(CSDN周赛第30期第四题,算法解析。)
__下一篇:__ 

我的HOT博:

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

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    打赏作者

    梦幻精灵_cq

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

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

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

    打赏作者

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

    抵扣说明:

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

    余额充值