【位运算-3】136.只出现一次的数字

题目描述:

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

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1 :

**输入:**nums = 2,2,1

**输出:**1

示例 2 :

**输入:**nums = 4,1,2,1,2

**输出:**4

示例 3 :

**输入:**nums = 1

**输出:**1

解题思路:

方法一:位运算

核心思路:异或运算

异或的性质:
性质 说明
a ^ a = 0 相同数异或为 0
a ^ 0 = a 任何数异或 0 等于自身
交换律 a ^ b = b ^ a
结合律 (a ^ b) ^ c = a ^ (b ^ c)
观察:

把所有数异或起来:

  • 出现两次的数异或后变成 0

  • 只出现一次的数异或后保留下来

复制代码
2 ^ 2 ^ 1 = 0 ^ 1 = 1
4 ^ 1 ^ 2 ^ 1 ^ 2 = 4 ^ (1^1) ^ (2^2) = 4 ^ 0 ^ 0 = 4

具体过程示例:

nums = [4,1,2,1,2]

复制代码
4 ^ 1 = 5
5 ^ 2 = 7
7 ^ 1 = 6
6 ^ 2 = 4

结果: 4 ✅

代码实现:

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result = 0;
        for (int num : nums) {
            result ^= num;
        }
        return result;
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n) 一次遍历
空间复杂度 O(1) 只用一个变量

关键细节:

1. 为什么异或能满足要求?
  • 出现两次的数:a ^ a = 0,互相抵消

  • 只出现一次的数:a ^ 0 = a,保留下来

  • 异或满足交换律和结合律,顺序不影响结果

2. 如果出现三次呢?

异或就不行了,需要用位计数:统计每一位 1 的个数,对 3 取模。

137 题:只出现一次的数字 II(其余出现三次)

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result = 0;
        for (int i = 0; i < 32; i++) {
            int count = 0;
            for (int num : nums) {
                count += (num >> i) & 1;
            }
            if (count % 3 != 0) {
                result |= (1 << i);
            }
        }
        return result;
    }
};

3. 如果出现两次的有两个呢?

260 题:只出现一次的数字 III(有两个只出现一次的数)

需要先用异或找到分组依据,再分组异或。

方法二:哈希表(O(n) 空间)

代码实现:

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> count;
        for (int num : nums) count[num]++;
        
        for (auto& [num, cnt] : count) {
            if (cnt == 1) return num;
        }
        return -1;
    }
};

复杂度:时间 O(n),空间 O(n)

缺点:不满足 O(1) 空间要求。

方法三:排序(O(n log n))

代码实现:

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size() - 1; i += 2) {
            if (nums[i] != nums[i+1]) return nums[i];
        }
        return nums.back();
    }
};

复杂度:时间 O(n log n),空间 O(1)

三种方法对比:

方法 时间复杂度 空间复杂度 推荐度
异或 O(n) O(1) ⭐⭐⭐⭐⭐
哈希表 O(n) O(n) ⭐⭐⭐
排序 O(n log n) O(1) ⭐⭐

总结:

要点 说明
核心思想 异或:相同为 0,不同为 1
关键性质 a ^ a = 0,a ^ 0 = a
时间复杂度 O(n)
空间复杂度 O(1)
相关推荐
Rabitebla31 分钟前
【Linux 底层原理】进程(十):进程等待详解---从僵尸进程到 wait、waitpid 与 status
linux·c++·笔记·学习·visual studio
西西弗Sisyphus3 小时前
C++ 超时互斥锁(Timed Mutex):std::timed_mutex 与 std::unique_lock
c++
其实防守也摸鱼4 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
今天要早睡_5 小时前
C++01_入门基础复习
开发语言·c++
Nuanyt5 小时前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
Fuyo_11197 小时前
C++ 运行时多态与虚函数机制全面剖析【面试重点】
开发语言·c++·面试
w_zero_one8 小时前
递归算法(一)
java·开发语言·算法
圣保罗的大教堂8 小时前
leetcode 3736. 最小操作次数使数组元素相等 III 简单
leetcode
文丑颜不良啊9 小时前
LeetCode1881~1990题目解析
java·leetcode