DAILY DOCDAILY DOC
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
  • Array

    • 数组
    • 二分查找
    • moveZeros
  • Dynamic-programming

    • 动态规划
  • 刷题指南
  • String

    • 字符串
  • bitwise-operator

    • 位运算符
  • heap
  • history

    • [1014] 最佳观光组合
    • [1022] 从根到叶的二进制数之和
    • [104] 二叉树的最大深度
    • [11] 盛最多水的容器
    • [110] 平衡二叉树
    • [1227] 飞机座位分配概率
    • [129] 求根节点到叶节点数字之和
    • [1306] 跳跃游戏 III
    • [148] 排序链表
    • 155.最小栈
    • [165] 比较版本号
    • 1763. 最长的美好子字符串
    • [1870] 准时到达的列车最小时速
    • [199] 二叉树的右视图
    • [21] 合并两个有序链表
    • 215.数组中的第 k 个最大元素
    • [2306] 公司命名
    • [234] 回文链表
    • [2516] 每种字符至少取 K 个
    • [316] 去除重复字母
    • [3171] 找到按位或最接近 K 的子数组
    • [322] 零钱兑换
    • [41] 缺失的第一个正数
    • [44] 通配符匹配
    • [494] 目标和
    • [509] 斐波那契数
    • [518] 零钱兑换 II
    • [62] 不同路径
    • [676] 实现一个魔法字典
    • 70 爬楼梯
    • [718] 最长重复子数组
    • [78] 子集
    • [82] 删除排序链表中的重复元素 II
    • [871] 最低加油次数
    • [88] 合并两个有序数组
    • [887] 鸡蛋掉落
    • 958.二叉树的完全性检验
    • [98] 验证二叉搜索树
    • [983] 最低票价
    • leetcode practice
    • 约瑟夫问题
    • 移除重复节点
  • linked-list

    • 706. 设计哈希映射
    • 链表
  • stack

    • stack
  • tree

    • Tree Traversal
    • 二叉树的最近公共祖先
    • 二叉树
    • 题目
  • leetCode 刷题
  • 回溯
  • 排序算法

[41] 缺失的第一个正数

要找到缺失的第一个正数,可以利用数组的索引进行原地哈希。这个方法的时间复杂度是 O(n)O(n)O(n),空间复杂度是 O(1)O(1)O(1)。算法的核心思想是把每个正数 xxx 放在数组的第 x−1x-1x−1 个位置上。这样最终数组中每个位置上存储的数值就是该位置的索引加 1。如果某个位置上不是期望的数值,那么这个位置的索引加 1 就是缺失的第一个正数。

算法步骤

  1. 遍历数组:将每个正数 xxx 放在数组的第 x−1x-1x−1 个位置上。如果 xxx 超出数组范围或者已经在正确位置上,则跳过。
  2. 再次遍历数组:检查每个位置 iii 是否存储了 i+1i+1i+1。
  3. 返回结果:如果发现第一个位置 iii 上的数值不是 i+1i+1i+1,则返回 i+1i+1i+1。如果所有位置都正确,则返回 n+1n+1n+1。

实现代码

var firstMissingPositive = function (nums) {
    const n = nums.length;

    // 把每个正数 x 放到位置 x-1 上
    for (let i = 0; i < n; i++) {
        while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] !== nums[i]) {
            [nums[nums[i] - 1], nums[i]] = [nums[i], nums[nums[i] - 1]];
        }
    }

    // 查找第一个位置 i 上不是 i+1 的数
    for (let i = 0; i < n; i++) {
        if (nums[i] !== i + 1) {
            return i + 1;
        }
    }

    // 如果都正确,返回 n+1
    return n + 1;
};

// 测试用例
console.log(firstMissingPositive([1, 2, 0])); // 输出: 3
console.log(firstMissingPositive([3, 4, -1, 1])); // 输出: 2
console.log(firstMissingPositive([7, 8, 9, 11, 12])); // 输出: 1

解释

  1. 遍历数组进行哈希:通过 while 循环将每个正数 xxx 放在数组的第 x−1x-1x−1 个位置上。利用交换操作来实现这一点。这个步骤会将数组中的正数按照其值调整到正确的位置上。
  2. 再次遍历数组:检查每个位置 iii 上的值是否等于 i+1i+1i+1。如果发现第一个位置 iii 上的数值不是 i+1i+1i+1,则 i+1i+1i+1 就是缺失的第一个正数。
  3. 返回结果:如果所有位置都正确,则返回 n+1n+1n+1。

这种方法的优势在于只需要常数空间,而且时间复杂度是线性的,非常高效。

Last Updated:
Contributors: rosendo
Prev
[322] 零钱兑换
Next
[44] 通配符匹配