LeetCode 丢失的数字:4 种解法一次讲清

13 阅读3分钟

这道题是数组题里的经典入门题,但非常适合用来训练解题思路的多样性

同一道题,可以用:

  • 额外数组
  • 排序
  • 哈希表
  • 数学公式

来解决。
这篇笔记我会从「最直观」一路推到「最优雅」。


一、题目回顾

给定一个长度为 n 的数组 nums,数组中包含 [0, n] 范围内的 n 个不同数字

也就是说:

  • 本来应该有 n + 1 个数字
  • 但现在缺失了一个

目标:

找出缺失的那个数字

二、方法一:额外数组

这是最容易想到的解法。

思路

  • 新建一个长度为 n + 1 的数组
  • 遍历 nums,把出现过的数字标记出来
  • 再遍历新数组,找到没被标记的位置

代码

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        int[] newNums = new int[n + 1];

        for (int num : nums) {
            newNums[num]++;
        }

        for (int i = 0; i <= n; i++) {
            if (newNums[i] == 0) {
                return i;
            }
        }
        return 0;
    }
}

分析

时间复杂度:

O(n)

空间复杂度:

O(n)

评价

  • 优点:思路简单,非常好理解
  • 缺点:额外空间开销大,不够优雅

三、方法二:排序后找位置不匹配

这是利用排序特性的解法。

思路

  • 排序后,理想状态是 nums[i] == i
  • 一旦发现不相等的位置,说明 i 就是缺失的数
  • 如果都匹配,缺的就是最后一个 n

代码

class Solution {
    public int missingNumber(int[] nums) {
        Arrays.sort(nums);

        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != i) {
                return i;
            }
        }
        return nums.length;
    }
}

分析

时间复杂度:

O(n log n)

空间复杂度:

O(1)(忽略排序栈)

评价

  • 优点:实现简单,逻辑直观
  • 缺点:排序的时间成本偏高

四、方法三:HashSet 去重查缺

这是**典型的“空间换时间”**思路。

思路

  • 把数组元素全部放进 HashSet
  • 0n 遍历
  • 第一个不在集合里的数字就是答案

代码

class Solution {
    public int missingNumber(int[] nums) {
        HashSet<Integer> set = new HashSet<>();

        for (int num : nums) {
            set.add(num);
        }

        for (int i = 0; i < nums.length; i++) {
            if (!set.contains(i)) {
                return i;
            }
        }
        return nums.length;
    }
}

分析

时间复杂度:

O(n)

空间复杂度:

O(n)

评价

  • 优点:查找速度快,逻辑清晰
  • 缺点:需要额外集合空间

五、方法四:数学公式(最推荐)

这是面试官最爱的一种解法

思路

  • [0, n] 的总和是:

    n * (n + 1) / 2
    
  • 实际数组中的元素和是 sum

  • 两者之差,就是缺失的数字

代码

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        int sum = 0;

        for (int num : nums) {
            sum += num;
        }

        int total = n * (n + 1) / 2;
        return total - sum;
    }
}

分析

时间复杂度:

O(n)

空间复杂度:

O(1)

评价

  • 优点:代码最简洁、效率最高
  • 缺点:需要对数学公式有敏感度

六、四种方法对比总结

方法时间复杂度空间复杂度特点
额外数组O(n)O(n)最直观
排序O(n log n)O(1)利用有序性
HashSetO(n)O(n)空间换时间
数学公式O(n)O(1)最优解

七、这道题真正想考什么?

这道题的本质并不是“找一个数”,而是考察:

  • 是否能从暴力解法逐步优化
  • 是否能想到用数学消除多余计算
  • 是否具备空间 / 时间复杂度权衡的意识

如果你能在面试中说出:

我知道 4 种解法,最优的是用数学公式

这道题基本稳了。