LeetCode 136. 只出现一次的数字(C语言详解 | 哈希表 + 排序 + 位运算)

一、题目描述

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

要求:

  • 时间复杂度 O(n)

  • 空间复杂度 O(1)

示例 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️⃣ 哈希表统计次数

2️⃣ 排序后成对查找

3️⃣ 位运算(最优解)

下面逐一介绍。


三、解法一:哈希表

思路

使用哈希表统计每个数字出现的次数:

  1. 遍历数组

  2. 统计每个数字出现次数

  3. 找到出现一次的数字

由于题目范围为:

复制代码
-30000 ~ 30000

可以直接用 数组模拟哈希表


C语言代码

复制代码
#include <stdlib.h>

int singleNumber(int* nums, int numsSize) {
    
    int offset = 30000;
    int hash[60001] = {0};
    
    for(int i = 0; i < numsSize; i++)
    {
        hash[nums[i] + offset]++;
    }
    
    for(int i = 0; i < 60001; i++)
    {
        if(hash[i] == 1)
            return i - offset;
    }
    
    return 0;
}

复杂度分析

复制代码
时间复杂度:O(n)
空间复杂度:O(n)

缺点:不满足题目 常量空间要求


四、解法二:排序

思路

先排序,然后每两个元素检查一次:

复制代码
1 1 2 2 4
      ↑

如果某个元素 和相邻元素不同,说明它只出现一次。


C语言代码

复制代码
#include <stdlib.h>

int cmp(const void* a, const void* b)
{
    return (*(int*)a - *(int*)b);
}

int singleNumber(int* nums, int numsSize) {
    
    qsort(nums, numsSize, sizeof(int), cmp);
    
    for(int i = 0; i < numsSize - 1; i += 2)
    {
        if(nums[i] != nums[i+1])
            return nums[i];
    }
    
    return nums[numsSize - 1];
}

复杂度分析

复制代码
时间复杂度:O(n log n)
空间复杂度:O(1)

缺点:排序导致时间复杂度不满足题目要求。


五、解法三:位运算(最优解)

核心思想

利用 异或 XOR 运算

异或的三个重要性质:

复制代码
a ^ a = 0
a ^ 0 = a
满足交换律和结合律

例如:

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

所有 成对出现的数字都会抵消,最后剩下的就是只出现一次的数字。


算法步骤

  1. 定义变量 res = 0

  2. 遍历数组

  3. 每个元素与 res 做异或

  4. 最终 res 即为答案


C语言代码

复制代码
int singleNumber(int* nums, int numsSize) {
    
    int res = 0;
    
    for(int i = 0; i < numsSize; i++)
    {
        res ^= nums[i];
    }
    
    return res;
}

执行过程示例

输入:

复制代码
[4,1,2,1,2]

计算过程:

复制代码
res = 0

0 ^ 4 = 4
4 ^ 1 = 5
5 ^ 2 = 7
7 ^ 1 = 6
6 ^ 2 = 4

最终结果:

复制代码
4

复杂度分析

复制代码
时间复杂度:O(n)
空间复杂度:O(1)

满足题目要求,是 最优解法


六、总结

解法 时间复杂度 空间复杂度 推荐
哈希表 O(n) O(n)
排序 O(n log n) O(1)
位运算 O(n) O(1) ⭐⭐⭐

最佳方案:位运算(XOR)

原因:

  • 时间复杂度 O(n)

  • 空间复杂度 O(1)

  • 代码简洁


本题属于经典位运算题,也是面试高频题。

相关推荐
古译汉书2 小时前
【数据结构算法】二分查找
c语言·开发语言·数据结构·c++·算法
逆境不可逃2 小时前
【从零入门23种设计模式19】行为型之观察者模式
java·开发语言·算法·观察者模式·leetcode·设计模式·动态规划
小龙报2 小时前
【算法通关指南:算法基础篇】二分答案专题:1.木材加工 2.砍树
c语言·数据结构·c++·算法·启发式算法
炸膛坦客2 小时前
单片机/C语言八股:(十一)指针的补充,包括指针的类型和大小
c语言·开发语言·单片机
cici158742 小时前
经典的基于策略迭代和值迭代法的动态规划MATLAB实现
算法·matlab·动态规划
月明长歌2 小时前
【码道初阶-Hot100】 LeetCode 49. 字母异位词分组:从排序哈希到分组映射,彻底讲透为什么排序后可以作为同一组的标识
算法·leetcode·哈希算法
big_rabbit05022 小时前
[算法][力扣242]有效的字母异位词
java·前端·leetcode
Q一件事2 小时前
结构方程相关
python·算法·机器学习
yugi9878382 小时前
兰伯特问题求解的MATLAB实现
开发语言·算法·matlab