Leetcode 41 firstMissingPositive

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

输入: [1,2,0]
输出: 3
输入: [3,4,-1,1]
输出: 2
输入: [7,8,9,11,12]
输出: 1

代码:

class Solution {
public:
    int firstMissingPositive(vector<int> A) {
        int i,j;
        int n=A.size();
        for(i=0;i<n;i++){
            int cur=A[i];
            // if in place or non-pos or out of bounds, skip.
            if(cur==i+1||cur<=0||cur>n)continue;
            swap(A[i],A[cur-1]);
            // if not the same, then reprocess it.
            if(A[i]!=A[cur-1])
                i--;
        }
        
        for(i=0;i<n;i++)
            if(A[i]!=i+1) 
                return i+1;
        return n+1;
    }
};

具体来分析一下这个代码:

乍一看,if(cur==i+1||cur<=0||cur>n)continue;似乎没什么大用处,但这句话配合swap其实发挥了至关重要的作用。另外判断A[i]和A[cur-1]看起来很奇怪,不过这其实是为了避免无限循环,一直交换。在排除了 负数、大于范围的数、重复的数、以及合适的数(正确位置的数)之后,那么交换过来的就只可能是不合适的数,这时就要一直循环交换指定位置的数字了。

算法思想是:


1.扫描一遍数组,得到当前索引和当前元素,如果索引和元素不相同,也就是这个元素出现在了不合适的位置,就交换它,交换的对象是这个元素值应该出现的位置。

2. 当我把应该出现的位置的元素调换过来之后,会有什么情况呢?

    a. 如果交换来的数字是正确的数字,就跳过这个i了,进行下一个i

    b. 如果交换过来的数字是负数,那就让这个负数来占这个位置的坑,如果大于了应该的范围n,也来占坑,就进行下一个i

    c. 如果交换过来的数字和自己相同的话,就说明这会陷入无限的交换之后,我们要阻止这种情况的发生,所以也进行下一个i

    d. 如果这个数字范围不出格,而且也和之前不同的话,就可以在这个索引i位置上一直交换下去,直到出现a.b.c的情况

3.当我们这样扫描一遍数组之后,就再扫描一遍数组,找出第一个位置与元素对不上的数字,得到结果


最后:如果题目问找到第一个缺失的非负数的话,就可以改写代码为(注意有两点要改,一是和谁交换,二是判断某一个元素的是否在合理范围内的这个范围变更了):

int firstMissingNotMinus(vector<int> A)
{
    for (int i = 0; i < A.size(); i++)
    {
        int cur = A[i];
        if (cur == i ||cur <0 || cur >=A.size()) continue;
        swap(A[i], A[cur]);
        if (A[i] != A[cur])
            i--;
    }
    for (int i = 0; i < A.size(); i++)
    {
        if (A[i] != i)
            return i;
    }
    return A.size();
}

延申:

这个题跟剑指offer第三题很像,不过剑指offer第三题限制了数据元素范围,不再考虑负数、超范围的数,且直接求出重复的数字,因此相较于这个题目简单很多。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值