41. First Missing Positive

输入:一个没有排序的正数数组nums
输出:在 nums数组中未出现的最小的正整数
规则:数组中的元素可能是负数,也可能重复。要求时间复杂度O(n),空间复杂度O(1)。
分析:题目其实很简单,遍历一次放入map中。然后从1到n遍历,是否在map中存在。但是这样不符合空间复杂度。
分析2:力扣官方解答。首先我们不需要考虑负数、0,以及大于n+1的值。因为答案一定在[1,n+1]之间。因为空间限制条件,我们可以使用原数组实现一个map,类似布隆过滤器。我们假设修改之后nums[i]<0,表示i+1存在;否则i+1不存在。
具体实现算法是:
1 检查数组中1是否存在。不存在则返回1,否则进入2.
2 将数组中不在[1,n]之间的值都设置为1。
3 遍历数组,设置nums[nums[i] -1] = 负数,这里需要注意,元素值可能重复。
4 遍历数组,找到第一个nums[i]<0的元素返回。

说明:代码实现一些细节和算法过程略有不同。

public int firstMissingPositive(int[] nums) {
        int n  = nums.length;
        //检查1是否缺失
        int oneCount = 0;
        for(int num : nums){
            if(num==1){
                oneCount =1 ;
                break;
            }
        }
        
        if(oneCount == 0) return 1;
        
        
        if(n == 1) return 2;
        //替换无效数字为1
        for(int i=0; i < n; i++){
            if(nums[i] <=0  || nums[i]>n){
                nums[i] = 1;
            }
        }
        
        //一个布隆过滤器 nums[i] >0表示 i不存在;nums[i]<0,表示i存在。nums[0]代表n是否存在。 
        for(int i=0;i <n; i++){
            int a = Math.abs(nums[i]);
            if(a == n){
                nums[0] = - Math.abs(nums[0]);
            }else{
                nums[a] = -Math.abs(nums[a]);
            }
        }
        for(int i=1;i <n; i++){
            if(nums[i] > 0){
                return i;
            }
        }
        return nums[0] >0? n: n+1;
    }

分析3:其实也是用nums[i]的值表示i+1是不是存在。这里的判断依据是如果nums[i]=i+1,则说明i+1存在,否则不存在。这个方法实现的技巧是交换。上一个方法实现的技巧是替换。原链接

	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,i,nums[i]-1);
            }
        }
        
        for(int i=0;i <n; i++){
            if(nums[i] !=  i+1){
                return i+1;
            }
        }

        return n+1;
    }
    private void swap(int[] nums, int i, int j) {
        int  tmp = nums[i] ;
        nums[i] = nums[j];
        nums[j] = tmp;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值