LeetCode 136. 只出现一次的数字:线性时间+常量空间最优解拆解

刷题路上,总会遇到一些看似简单却暗藏巧思的题目,LeetCode 136. 只出现一次的数字就是其中之一。这道题不仅考察对数组的基本操作,更核心的是对「位运算」的灵活运用------既要满足线性时间复杂度,又要控制常量额外空间,常规思路很容易陷入瓶颈,而最优解却简洁到让人眼前一亮。

一、题目解析:明确约束,找准核心

先再仔细读一遍题目,避免遗漏关键条件:

给定一个非空整数数组 nums,除了某个元素只出现一次以外,其余每个元素均出现两次。要求找出那个只出现了一次的元素。

最关键的约束的是:必须设计线性时间复杂度(O(n))的算法,且只使用常量额外空间(O(1))。

这里要注意两个坑:

  • 不能用哈希表(HashMap):虽然哈希表可以做到O(n)时间,但空间复杂度是O(n),不符合常量空间要求;

  • 不能用排序+遍历:排序的时间复杂度是O(n log n),超出了线性时间的限制;

  • 不能用双重循环:时间复杂度是O(n²),同样不满足要求。

所以,这道题的核心考点,不是数组遍历,而是「如何用位运算实现无额外空间的去重匹配」。

二、最优解法:异或运算(^)的妙用

这道题的最优解,就是利用异或运算的三个核心性质,直接实现线性时间、常量空间的求解,先看最终代码(题目给出的代码已最优,我们逐行拆解):

typescript 复制代码
function singleNumber(nums: number[]): number {
  let res = 0;
  for (const num of nums) {
    res ^= num;
  }
  return res;
};

代码只有5行,却完美满足所有约束,关键就在于「res ^= num」这一步。要理解它,必须先掌握异或运算的三个核心性质(记牢这三点,类似题目都能秒解):

1. 异或运算的核心性质

  • 性质1:任何数与0异或,结果还是它本身(a ^ 0 = a)。比如 5 ^ 0 = 5,0 ^ (-3) = -3;

  • 性质2:任何数与自身异或,结果为0(a ^ a = 0)。比如 3 ^ 3 = 0,10 ^ 10 = 0;

  • 性质3:异或运算满足交换律和结合律(a ^ b ^ c = a ^ c ^ b = (a ^ b) ^ c)。也就是说,运算顺序不影响最终结果。

2. 解法逻辑拆解

结合题目条件(除一个元素外,其余元素均出现两次),我们可以利用异或的性质推导:

假设数组为 a, b, a, c, b,其中 c 是只出现一次的元素。将数组中所有元素依次异或:

res = 0 ^ a ^ b ^ a ^ c ^ b

根据交换律和结合律,调整顺序:

res = (a ^ a) ^ (b ^ b) ^ (0 ^ c)

再根据性质1和性质2,简化后:

res = 0 ^ 0 ^ c = c

也就是说,遍历数组,将所有元素与初始值0进行异或,最终的结果就是那个只出现一次的元素------因为所有出现两次的元素,异或后都会抵消为0,最后只剩下单独的那个元素。

三、代码逐行解析,一看就懂

再回到代码,逐行拆解每一步的作用,确保理解无死角:

  1. 「let res = 0;」:初始化结果变量为0,因为异或运算的初始值设为0,才能满足「0 ^ 元素 = 元素」的性质,为后续运算铺垫;

  2. 「for (const num of nums)」:遍历数组中的每一个元素,时间复杂度为O(n),符合线性时间要求;

  3. 「res ^= num;」:等价于「res = res ^ num」,将当前res与数组元素逐次异或,利用异或的性质抵消重复元素;

  4. 「return res;」:遍历结束后,res的值就是只出现一次的元素,直接返回即可。

四、总结:这道题的核心收获

这道题看似简单,却能帮我们跳出「常规遍历、哈希表」的固定思维,学会用位运算解决「去重、匹配」类问题------尤其是当题目限制「常量空间」时,异或运算往往是最优选择。

核心要点回顾:

  • 异或运算的三个性质是解题关键,一定要牢记;

  • 线性时间(O(n))+ 常量空间(O(1))的最优解,只能通过位运算实现;

  • 代码简洁,但背后的逻辑需要结合异或性质推导,理解本质比死记代码更重要。

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
倒头就睡的小比特4 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
猎头南楼4 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
旖旎夜光4 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控