41. 缺失的第一个正数

  1. 题目链接

  2. 解题思路:整体思路就是,我们先假想,[0, n - 1]上,放满了1~n,所以,我们缺失的第一个正数就是n+1。也就是说,i下标,放的数字是i+1。那么我们从左往右遍历的过程中,就尽量满足这种情况

    • 1️⃣如果nums[i] == i + 1,直接跳过,啥都不管
    • 2️⃣如果nums[i] <= 0,那么,我们就「发货」到「无效区」。「无效区」是什么,我们可以理解是「当前状况下,没有必要处理的区域」,用R来表示,即[R, n - 1]是无效区。而R+1就是我们的答案。
      • 怎么理解,为什么要有这么个东西?
      • 我们可以把nums划分成几个区域,[0, i]就是我们处理过的区域,这部分的数据都是符合我们的预期,就是i下标,放i+1的数字。[i + 1, R - 1]就是我们还未处理过的数字。[R, n - 1]就是无效区。
      • 为啥需要无效区?因为我们在[i+1, R-1]这个区域时,如果遇到不符合我们的预期时,我们怎么处理这个数字?我们可以把这个数字扔到「无效区」,同时把R-1的数字放回到i位置来(和快排交换时,一样的操作),然后无效区范围扩大。
    • 3️⃣如果nums[nums[i] - 1] == nums[i],和2️⃣操作类似
      • 因为我现在想把nums[i]放到下标为nums[i] - 1的位置,但是,如果这个位置的数已经是nums[i]了,那么就要放到「无效区」
    • 4️⃣交换i位置和nums[i] - 1位置的数
  3. 代码

    class Solution {
    public:
    int firstMissingPositive(vector<int>& nums) {
    // 我们假想最「差」的情况,就是[0, n - 1]上分别是1~n,也就是说,nums[i]位置放置的数是i+1,那么,缺失的第一个正数就是n+1
    int n = nums.size();
    int R = n; // R + 1就是缺失的第一个正数 同时,不在我们预料中的数,放在[R, n - 1]中,称之为无效区
    int L = -1; // [0, L]就是我们所说的nums[i]放置的数是i+1
    int i = 0;
    while(i < R) {
    if (nums[i] == i + 1) { // 符合预期,不用管
    i++;
    } else if (nums[i] <= 0) { // 不符合预期 「发货」到无效区
    R--;
    nums[i] = nums[R]; // 为什么不把nums[i]放到无效区来?因为无效区的数我们直接不会处理了
    } else { // nums[i] 我想放在nums[i]-1上
    int index = nums[i] - 1;
    // 假设 nums[i] = 4,我想放到下标3中,但是如果下标3就是4呢?那么就多余了,所以「发货」到无效区
    if (index >= R || nums[index] == nums[i]) {
    R--;
    nums[i] = nums[R];
    } else {
    int tmp = nums[i];
    nums[i] = nums[index];
    nums[index] = tmp;
    }
    }
    }
    return R + 1;
    }
    };
posted @   ouyangxx  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示