题目描述
思路解析动画文字版
下面 15 步动画会按主解代码推进,而不是泛泛讲题型。
1. 看输入:输入 nums = [2,2,3,2]。三个 2 各出现三次、一个 3 只出现一次,答案应是 3。要求线性时间、常数空间,所以不用哈希计数,改用按位统计。
2. 核心思路:逐位数 1:思路:把每个数看成二进制。2 = 10,3 = 11。对某一位,把所有数在该位的 1 加起来,出现三次的数贡献 3 的倍数,对 3 取模后只剩唯一数在这一位的贡献。
3. 看第 0 位(最低位):进入主循环,先看第 0 位(最低位)。把计数器 cnt 清零,橙色指向第一个数 nums[0]=2。2 = 二进制 10,它的第 0 位是 0。
4. 第 0 位:数 nums[0]=2:数 nums[0]=2:(2 >> 0) & 1 = 0,第 0 位是 0,cnt 加 0 仍为 0。该数已计入,标蓝。
5. 第 0 位:数 nums[1]=2:数 nums[1]=2:第 0 位还是 0,cnt 加 0 仍为 0。橙色移到下标 1,前两个数都已计入。
6. 第 0 位:数 nums[2]=3:数 nums[2]=3:3 = 二进制 11,第 0 位是 1,cnt 从 0 加到 1。这就是唯一数 3 在第 0 位的贡献。
7. 第 0 位:数 nums[3]=2:数 nums[3]=2:第 0 位是 0,cnt 加 0 仍为 1。四个数全部数完,第 0 位上的 1 总共有 1 个。
8. 第 0 位结算:cnt % 3:第 0 位结算:cnt=1,1 % 3 = 1 不为 0,说明唯一数在这一位是 1(来自绿色的 3)。把这一位写进 ans:ans 变为二进制 1,即 1。
9. 看第 1 位:进入第 1 位,cnt 重新清零。2 = 二进制 10、3 = 二进制 11,它们的第 1 位都是 1,下面逐个数。
10. 第 1 位:数前两个 2:nums[0]=2 第 1 位是 1,cnt 到 1;nums[1]=2 第 1 位也是 1,cnt 到 2。两个数都已计入(标蓝)。
11. 第 1 位:数 nums[2]=3:nums[2]=3:(3 >> 1) & 1 = 1,第 1 位是 1,cnt 从 2 到 3。
12. 第 1 位:数 nums[3]=2:nums[3]=2 第 1 位是 1,cnt 到 4。四个数全部数完,第 1 位上的 1 总共有 4 个。
13. 第 1 位结算:cnt % 3:第 1 位结算:cnt=4,4 % 3 = 1 不为 0(三个 2 贡献了 3 个,剩下 1 个来自唯一数 3)。把第 1 位写进 ans:ans 从 1 变成二进制 11,即十进制 3。
14. 高位第 2~31 位全是 0:第 2 位到第 31 位:2 和 3 都很小,这些高位上都是 0,每位 cnt 都为 0,0 % 3 = 0,ans 不再改变。所有都是正数,无需补码还原。
15. 返回答案:所有 32 位处理完,ans = 二进制 11 = 3。返回 3,正是数组里只出现一次的数(绿色标出)。三个 2 在每一位的贡献都被模 3 抵消掉了。
记住这题的代码骨架:题意约束先落到状态变量,再用循环或递归维护它。
参考代码
class Solution: def singleNumber(self, nums): ans = 0 for i in range(32): cnt = 0 for x in nums: cnt += (x >> i) & 1 if cnt % 3: ans |= 1 << i if ans >= 2 ** 31: ans -= 2 ** 32 return ans复杂度
- 时间复杂度:O(32n),统计 32 位
- 空间复杂度:O(1),固定变量
易错点
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
只出现一次的数字 III
LeetCode 260 · 中等 · 沿着 位运算套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题