【LeetCode Hot 100】 136. 只出现一次的数字
问题链接
136. 只出现一次的数字
问题描述
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入:nums = [2,2,1]
输出:1
示例 2 :
输入:nums = [4,1,2,1,2]
输出:4
示例 3 :
输入:nums = [1]
输出:1
提示:
1 <= nums.length <= 3 * 10^4-3 * 10^4 <= nums[i] <= 3 * 10^4- 除了某个元素只出现一次以外,其余每个元素均出现两次。
问题解答
一、最优解法:位运算(异或)
1. 解法原理
题目要求 线性时间复杂度(O(n)) 和 常量额外空间(O(1)),异或(XOR)运算恰好满足这两个约束,其核心性质如下:
- 交换律:
a ^ b ^ c = a ^ c ^ b(元素顺序不影响结果) - 归零性:
a ^ a = 0(重复元素异或后抵消为 0) - 恒等性:
a ^ 0 = a(最终剩余的非重复元素与 0 异或后保留自身)
遍历数组时,将所有元素依次异或,重复元素会相互抵消为 0,最终结果就是「只出现一次的数字」。
2. Java 代码实现
class Solution {public int singleNumber(int[] nums) {// 初始值设为 0,因为 0 与任何数异或都等于该数本身int result = 0;// 遍历数组,依次对每个元素进行异或运算for (int num : nums) {result ^= num;}// 最终 result 即为只出现一次的数字return result;}
}
3. 复杂度分析
- 时间复杂度:O(n),仅遍历数组一次,每个元素的异或运算为 O(1)。
- 空间复杂度:O(1),仅使用一个变量
result存储中间结果,无额外空间消耗。
二、其他常见解法(供对比)
1. 哈希表(HashMap)
思路
- 遍历数组,用
HashMap存储「元素值 → 出现次数」的映射。 - 再次遍历
HashMap,找到值为 1 的键(即只出现一次的数字)。
代码实现
import java.util.HashMap;
import java.util.Map;class Solution {public int singleNumber(int[] nums) {Map<Integer, Integer> countMap = new HashMap<>();// 统计每个元素的出现次数for (int num : nums) {countMap.put(num, countMap.getOrDefault(num, 0) + 1);}// 找到出现次数为 1 的元素for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {if (entry.getValue() == 1) {return entry.getKey();}}// 题目保证数组非空且存在唯一解,此处仅为语法兼容return -1;}
}
复杂度分析
- 时间复杂度:O(n),两次遍历(数组 + 哈希表)。
- 空间复杂度:O(n),哈希表最多存储 n-1 个重复元素和 1 个目标元素,空间与数组长度正相关。
2. 数组计数(针对题目值域约束)
思路
题目明确 nums[i] 范围为 -3*10^4 ~ 3*10^4,可通过「偏移量」将负数映射为非负索引(如 num + 30000),用数组记录元素出现次数,最后找到计数为 1 的元素。
代码实现
class Solution {public int singleNumber(int[] nums) {// 偏移量:将 -30000 映射为 0,30000 映射为 60000int offset = 30000;int[] countArr = new int[60001]; // 索引范围 0~60000// 统计每个元素的出现次数for (int num : nums) {countArr[num + offset]++;}// 找到计数为 1 的元素(反向计算原数值:索引 - 偏移量)for (int i = 0; i < countArr.length; i++) {if (countArr[i] == 1) {return i - offset;}}return -1; // 语法兼容,题目保证有解}
}
复杂度分析
- 时间复杂度:O(n),两次遍历(数组 + 计数数组)。
- 空间复杂度:O(1)?注意:虽然计数数组长度固定(60001),但本质是「常量空间」的特例,不过仍不如异或解法简洁(异或仅用 1 个变量)。
三、总结
| 解法 | 时间复杂度 | 空间复杂度 | 核心优势 |
|---|---|---|---|
| 异或运算 | O(n) | O(1) | 完全满足题目约束,最优解 |
| 哈希表 | O(n) | O(n) | 思路直观,适用于一般场景 |
| 固定长度数组 | O(n) | O(1) | 依赖题目值域约束,灵活性低 |
