一文吃透只出现一次的数字 II!LeetCode 261「只出现一次的数字 II」两大解法多语言题解

一、题目简介

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法)

步骤详解
  1. 对每个二进制位(0~31),统计所有数字该位出现1的次数。
  2. 对每位计数对3取余,剩下的就是只出现一次的数字在该位的状态。
  3. 合成最终答案。
优缺点
  • 时间O(32n)=O(n),空间O(1)。
  • 适合大数据且极高效,面试加分项。

方案二:哈希表统计

步骤详解
  1. 用哈希表统计每个数字出现次数。
  2. 遍历哈希表,返回次数为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次及其他数位计数题,是刷题与面试核心必修题型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据分析螺丝钉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值