【经典题目】缺失的第一个正数——原地哈希表,维护连续序列长

来源于Leetcode的第41题, 难度H
在这里插入图片描述

完成这个任务其实不算复杂,只需要使用set去重,然后依次查找。只是题目限制了算法复杂度和使用的空间。我们希望原地实现,且复杂度是N

一个有意思的思路是原地进行hash,思想是每次进行替换,把某个数字放到该数字的索引位置,最后检查哪个数字位置缺失即可。

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        for (int i = 0;i<n;i++){
            while(nums[i]>0 && nums[i]<=n && nums[nums[i]-1] != nums[i]){
                swap(nums, nums[i]-1, i);
            }
        }
        for(int i = 0;i<n;i++){
            if (nums[i]<0 || nums[i]>n || nums[i]-1!=i){
                return i+1;
            }
        }
        return n+1;
    }
    private void swap(int[] nums, int x, int y){
        int cur = nums[x];
        nums[x] = nums[y];
        nums[y] = cur;
    }
}

另外一个思路是是借助数组的索引,实现原地的哈希表。对于数组中的数字,我们将该数组对应的索引的数字设置为负数,最后我们遍历整个数组,发现的第一个不是负数的数字的索引就是缺失的。

这种方法我们首先需要进行预处理数组,将数组中小于等于0和大于n的数字都设为1,并且在处理索引时考虑,当数字为n对应到0的索引。

最后考虑特殊情况,首先是考虑1是否在其中,其次是先从1开始检查数组,如都为负数,再检查0的位置返回N。否则的话返回n+1.

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        n = len(nums)
        # 基本情况
        if 1 not in nums:
            return 1
            
        for i in range(n):
            if nums[i] <= 0 or nums[i] > n:
                nums[i] = 1
        
        for i in range(n): 
            a = abs(nums[i])
            if a == n:
                nums[0] = - abs(nums[0])
            else:
                nums[a] = - abs(nums[a])
        print(nums)
        for i in range(1, n):
            if nums[i] > 0:
                return i
        # 这个判断的顺序很重要,按照顺序判断
        if nums[0] > 0:
            return n
            
        return n + 1

还可以通用的采用维护连续的序列的方法

class Solution(object):
    def firstMissingPositive(self, nums):
        ## 利用哈希表,维护左右区间
        # 注意一定要去重
        nums = list(set(nums))
        left = {}
        right = {}
        n = len(nums)
        for i in nums:
            if i > 0:
                if i-1 in left and i+1 in right:
                    left[right[i+1]] = left[i-1]
                    right[left[i-1]] = right[i+1]
                elif i-1 in left:
                    left[i] = left[i-1]
                    right[left[i-1]] = i
                elif i+1 in right:
                    right[i] = right[i+1]
                    left[right[i+1]] = i
                else:
                    left[i] = i
                    right[i] = i
        if 1 in right:
            return right[1]+1
        else:
            return 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值