268. 丢失的数字

难度:简单 | 主题:数学 / 位运算 / 哈希表

题目

给定一个包含 [0, n] 中 n 个数的数组 nums,找出这个范围内没有出现在数组中的那个数。

示例

 
nums = [3, 0, 1]  →  2
 
解释:n=3,完整范围 [0,1,2,3] 中缺失 2
 

思路

先讲个故事:幼儿园点名

老师拿着花名册(0 号到 n 号)点名,发现 少了一个人。但花名册上没标谁是几号——只能自己算。

你怎么快速找到那个没来的小朋友?


引导式推导:三种思路,两种最优

方法一:数学法——高斯求和

完整范围 [0, n] 的总和 = n(n+1)/2,减去数组实际总和,差值就是缺失的数。

 
n = len(nums)          # n=3, 范围 [0,3] 共 4 个数
 
expected = 3*4//2 = 6  # 0+1+2+3 = 6
 
actual = 3+0+1 = 4     # 数组里有的
 
missing = 6 - 4 = 2    # ✓
 

方法二:位运算法——异或抵消

利用 a ^ a = 0:把 [0, n] 所有数和数组里所有数一起异或,出现两次的抵消为 0,只剩缺失的数。

 
范围:  0 ^ 1 ^ 2 ^ 3       = 此范围异或值
 
数组:  ^ 3 ^ 0 ^ 1         = 异或上数组中所有数
 
结果:  (0^0) ^ (1^1) ^ 2 ^ (3^3) = 0 ^ 0 ^ 2 ^ 0 = 2
 

graph LR

    A["初始化 xor = n"] --> B["遍历 i, nums[i]"]

    B --> C["xor ^= i ^ nums[i]"]

    C --> D["出现两次的抵消<br/>只剩缺失的数"]

    D --> E["返回 xor"]


多解法对比

做法时间空间特点
数学法O(n)O(1)最直观,一行代码
位运算O(n)O(1)酷炫,不怕溢出
排序 + 下标O(n log n)O(log n)最笨但可靠
哈希集合O(n)O(n)空间换时间

代码

 
def missingNumber(self, nums):
 
    n = len(nums)
 
    return n * (n + 1) // 2 - sum(nums)   # 期望总和 - 实际总和
 

复杂度

指标解释
时间O(n)sum(nums) 需遍历
空间O(1)常数变量

实战考量

延伸思考

Q:为什么数学法要注意用 // 而不是 /

A:Python 中 / 返回浮点数,大 n 时可能丢失精度。// 是整数除法,精确无误。

Q:异或法的原理是什么?能一步步拆解吗?

A:xor 初始化为 n(因为 n 在范围里但不在数组下标范围里)。然后遍历 (i, num)xor ^= i ^ num。下标 i 和数值 num 完美配对——出现两次的抵消为零,剩下缺失的数。

Q:如果改成 [1, n] 而不是 [0, n] 呢?

A:数学法:(1+n)*n/2 - sum(nums)。异或法:xor 初始化为 0,遍历时 xor ^= (i+1) ^ num

Q:如果缺失两个数呢?

A:先算总和差和平方和差 → 解方程组。或者异或后得到 a ^ b,根据最低不同位分成两组分别异或。

Q:跟 136只出现一次的数字 有什么区别?

A:那题是找数组中出现一次的数(其他都出现两次),这题是缺失的数。但核心思想相通——都是利用异或 a ^ a = 0 的抵消性质。

易错点

  • 高斯求和用 // 不是 /

  • 数组长度 n 对应范围 [0, n]n+1 个数

  • 异或法记得 xor 初始值 = len(nums)(不是 0)

  • 不要惯性思维走排序/哈希——有更优解法


生活类比

数学法 → 老师查人数

老师知道花名册上应该是 0 到 n 号,心算总人数,然后数一遍教室里实际的人数,差就是没来的。

不翻名单、不排序——脑子算总和就行。


相关题目

题目关系
136只出现一次的数字位运算同族,都是利用异或找唯一元素
41缺失的第一个正数原地哈希进阶版,O(1) 空间找缺失的最小正数

→ 返回题单:LeetCode学习路线图 > 一、数组与哈希(含双指针、矩阵)

速记卡(面试闪卡)

Q1:一句话讲清「268. 丢失的数字」到底是什么?

A:在 [0,n] 中 n 个数缺一个,找出没出现的那个数。

Q2:题目 —— 怎么理解?

A:像老师点名少一人:给 n 个数覆盖 [0,n] 范围却缺一个,找出缺席的那位。比如 [3,0,1] 缺 2,n=3 完整范围是 0~3 共四个数。

Q3:思路 —— 怎么理解?

A:两种最优解法:数学法(高斯求和)算期望总和 n(n+1)/2 减实际和得差值;位运算(异或抵消)把 0~n 与数组所有数一起异或,出现两次的抵消为 0,只剩缺失数。

Q4:代码 —— 怎么理解?

A:一行解题:return n*(n+1)//2 - sum(nums)。异或版则 xor 初值设为 n,遍历时 xor ^= i ^ nums[i],最后剩下的就是答案,不怕大数溢出。

Q5:复杂度与实战考量 —— 怎么理解?

A:时间 O(n)(遍历求和/异或),空间 O(1)(常数变量)。注意用 // 整数除防浮点精度丢失;异或法 xor 初值是 len(nums) 不是 0;别惯性走排序/哈希,有更优解。

Q6:核心速记主线有哪些?

  • 数学法:期望和减实际和

  • 异或法:抵消成对得缺失

  • 时间 O(n)、空间 O(1)

  • 易错:// 整除、xor 初值=n

口诀

A:丢失数字别乱找,高斯求和差一出;

异或抵消成对消,剩下便是缺席徒;

时间 On 空间一,整数除法莫糊涂;

xor 初值要设 n,一遍写对稳如故。

相关链接