[leetcode 41]缺失的第一个正数(Python+哈希表+元素互换)

题目描述

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-missing-positive


结题思路

来源于官方题解:

哈希表:

哈希表是一个可以支持快速查找的数据结构,给定一个元素,我们可以在O(1)的时间查找该元素是否在哈希表中。为了满足题目要求的时空复杂度,可以考虑将给定的数组设计成哈希表的替代品。

对于一个长度为N的数组,没有出现的最小正整数一定在[1, N+1]中。如果[1, N]都出现了,答案就是N+1,否则就是[1, N]中没有出现的最小正整数。所以,只要将所有在[1, N]范围内的数放入哈希表就可以找到答案,而输入的数组长度就是N,所以可以加以利用。

  • 算法思路:
    对数组遍历,对于遍历到的数x,如果在[1, N]范围内,就将数组的第x-1个位置打上标记,遍历结束后如果所有位置都打上了标记则答案就是N+1,否则就是没打标记的最小的位置加1。
    至于如何打标记,由于数组中的数没有限制,但我们只在意[1, N]范围的数,所以可以先遍历数组,把不再该范围内的数改成任意一个大于N的数(比如N+1)。这样数组中的数都是正数了,就可以将负号作为标记。

- 算法流程如下:

  1. 将数组中所有<=0的数改成N+1;
  2. 遍历数组中的每个数,因为可能是重复的数,所以可能已经被打了标记。如果|x|∈[1, N],那么给数组中第|x|-1个位置的数加上负号,注意不要重复添加负号(所以只要先取绝对值再加负号就可以)。
  3. 在遍历数组找到第一个不为负数的数,返回这个位置+1;否则每一个数都为负,返回N+1。

- 复杂度分析

  1. 时间复杂度:O(N)
  2. 空间复杂度:O(1)

换位置:

将给定的数组恢复成如下形式:

如果数组中包含x∈[1, N],恢复后的第x-1的元素为x。

恢复后数组应该有[1, 2, 3, …, N]的形式,但是其中有的位置上的数是错误的,正代表着缺失的正数。

比如:[3, 4, -1, 1],置换后的数组为[1, -1, 3, 4],所以缺失的数是2。

  • 置换过程如下:
    遍历数组,对于x=nums[i],如果x∈[1, N],则x应该出现在数组中的 x-1 的位置。完成交换后,新的nums[i]可能还在[1, N]范围内,需要继续进行交换操作直到x不属于[1, N]。
    为了避免死循环,如果nums[i] = x = nums[x-1],则x已经出现在了正确位置,则跳出循环遍历下一个数。
    每次交换都会使一个数被交换到正确位置,故交换次数最多为N,算法的时间复杂度为O(N)。

代码实现

哈希表:

def firstMissingPositive(self, nums):
        n = len(nums)
        for i in range(n):
            if nums[i] <= 0:
                nums[i] = n+1

        for i in range(n):
            tmp = abs(nums[i])
            if tmp < n+1:
                nums[tmp-1] = -abs(nums[tmp-1])

        for i in range(n):
            if nums[i] > 0:
                return i+1
        
        return n+1

换位置:

class Solution(object):
    def firstMissingPositive(self, nums):
        n = len(nums)
        for i in range(n):
            while 1 <= nums[i] <= n and nums[i] != nums[nums[i]-1]:
                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  

Tips

  1. Python里两元素置换可以直接: a,b=b,a。
  2. 哈希表非常适合快速查找元素。

A u t h o r : C h i e r Author: Chier Author:Chier

你可能感兴趣的:(有事没事刷刷oj,leetcode,算法,哈希表,python)