一、题目简介
LeetCode 261(实际上在力扣上为137)《只出现一次的数字 II》(Single Number II)是一道高频位运算题。给定一个整数数组,除了一个元素只出现一次,其他每个元素都出现三次,要求找出只出现一次的元素。这题是集合与计数类位运算的代表,考查编码巧思。
二、题目描述
给定一个整数数组 nums,除某个元素只出现一次外,其余每个元素均出现三次。请你找出那个只出现一次的元素。
三、示例分析
示例1:
输入: nums = [2,2,3,2]
输出: 3
- 2出现三次,3只出现一次。
示例2:
输入: nums = [0,1,0,1,0,1,99]
输出: 99
四、解题思路与详细步骤
方案一:位运算统计(每位模3法)
步骤详解
- 对每个二进制位(0~31),统计所有数字该位出现1的次数。
- 对每位计数对3取余,剩下的就是只出现一次的数字在该位的状态。
- 合成最终答案。
优缺点
- 时间O(32n)=O(n),空间O(1)。
- 适合大数据且极高效,面试加分项。
方案二:哈希表统计
步骤详解
- 用哈希表统计每个数字出现次数。
- 遍历哈希表,返回次数为1的元素。
优缺点
- 时间O(n),空间O(n)。
- 思路直观,代码简单。
五、代码实现(Python/Java/C++)
Python实现
解法一:位运算统计
def singleNumber(nums):
res = 0
for i in range(32):
cnt = 0
for num in nums:
# 注意处理负数
if (num >> i) & 1:
cnt += 1
if cnt % 3:
# 补符号位
if i == 31:
res -= (1 << 31)
else:
res |= (1 << i)
return res
解法二:哈希表统计
from collections import Counter
def singleNumber(nums):
count = Counter(nums)
for num in count:
if count[num] == 1:
return num
Java实现
解法一:位运算统计
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for (int i = 0; i < 32; i++) {
int cnt = 0;
for (int num : nums) {
if (((num >> i) & 1) != 0)
cnt++;
}
if (cnt % 3 != 0) {
if (i == 31) // 负数符号位
res -= (1 << 31);
else
res |= (1 << i);
}
}
return res;
}
}
解法二:哈希表统计
import java.util.*;
class Solution {
public int singleNumber(int[] nums) {
Map<Integer, Integer> count = new HashMap<>();
for (int num : nums)
count.put(num, count.getOrDefault(num, 0) + 1);
for (int num : count.keySet())
if (count.get(num) == 1)
return num;
return -1;
}
}
C++实现
解法一:位运算统计
#include <vector>
using namespace std;
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for (int i = 0; i < 32; ++i) {
int cnt = 0;
for (int num : nums)
if ((num >> i) & 1)
++cnt;
if (cnt % 3) {
if (i == 31) // 负数
res -= (1 << 31);
else
res |= (1 << i);
}
}
return res;
}
};
解法二:哈希表统计
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map<int, int> count;
for (int num : nums)
count[num]++;
for (auto& [num, c] : count)
if (c == 1)
return num;
return -1;
}
};
六、复杂度分析
- 方案一:O(n)时间,O(1)空间(常数级位操作)
- 方案二:O(n)时间,O(n)空间
七、边界与细节注意
- 可能有负数,需注意符号位
- 除目标元素外其他均出现三次
- 输入不为空
八、模拟面试环节及答案
1. 问:为啥按位计数对3取余就能还原只出现一次的数?
答:
其他数字每一位都贡献3的倍数,只有目标数的位能“剩下来”,合成后就是唯一数。
2. 问:如果有k个出现一次,其余出现m次呢?
答:
需对m取余,按位统计,复杂度不变。k>1时多返回几个数。
3. 问:负数如何处理?
答:
需特别处理符号位。Python可直接处理,Java/C++最后一位要用补码。
4. 问:如果哈希表解法被禁止?
答:
必须用位运算或有限状态机等O(1)空间做法,面试建议优先写位运算解法。
5. 问:能否只用一次循环实现位运算解法?
答:
有更高阶有限状态机(ones、twos位图法),面试可加分但易错,常用按位法。
九、总结升华
本题是位运算统计、计数和哈希映射的经典例子。掌握后可迁移到出现k次、m次及其他数位计数题,是刷题与面试核心必修题型。