news 2026/11/2 10:18:09

LeetCode 136题:哈希表、排序与位运算解法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 136题:哈希表、排序与位运算解法详解

1. 问题背景与核心解法

LeetCode 136题"只出现一次的数字"是算法入门经典题目,给定一个非空整数数组,其中某个元素只出现一次,其余每个元素均出现两次,要求找出那个只出现一次的数字。这道题看似简单,却蕴含着多种解题思路,特别适合用来理解不同算法思想的时间/空间复杂度差异。

在实际工程中,类似场景很常见——比如日志分析时找出异常请求ID,或数据库去重时识别唯一记录。这道题的三种主流解法恰好代表了算法设计的典型思路:

  • 暴力排序法(时间复杂度O(nlogn),空间复杂度O(n))
  • 哈希表计数法(时间复杂度O(n),空间复杂度O(n))
  • 位运算异或法(时间复杂度O(n),空间复杂度O(1))

2. C语言实现哈希表解法

2.1 哈希表设计思路

C标准库没有内置哈希表,需要手动实现。考虑到题目限制(数字范围在-3万到3万之间),可以采用简化版的开放寻址法:

#define HASH_SIZE 60001 #define OFFSET 30000 int hash[HASH_SIZE]; void initHash() { memset(hash, 0, sizeof(hash)); } void insert(int num) { hash[num + OFFSET]++; } int findSingle(int nums[], int numsSize) { initHash(); for(int i = 0; i < numsSize; i++) { insert(nums[i]); } for(int i = 0; i < numsSize; i++) { if(hash[nums[i] + OFFSET] == 1) { return nums[i]; } } return -1; // 题目保证有解,这里仅为容错 }

注意:这种实现利用了题目中数字范围有限的特性。若数字范围不限,需改用链表法处理冲突,或使用第三方库如uthash。

2.2 复杂度分析

  • 时间复杂度:O(n),两次线性遍历
  • 空间复杂度:O(k),k为数字范围(本例固定为60001)

3. 排序解法实现与优化

3.1 快速排序实现

C语言标准库的qsort非常适合这种场景:

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

3.2 边界情况处理

当唯一数字出现在数组末尾时,循环会遍历到倒数第二个元素,因此需要单独返回最后一个元素。这是该解法最容易出错的地方。

4. 位运算的魔法解法

4.1 异或运算特性

这是本题的最优解,利用异或的三个性质:

  1. a ^ 0 = a
  2. a ^ a = 0
  3. 交换律:a ^ b ^ a = (a ^ a) ^ b = 0 ^ b = b
int singleNumber(int* nums, int numsSize) { int result = 0; for(int i = 0; i < numsSize; i++) { result ^= nums[i]; } return result; }

4.2 为什么这个方法有效?

假设数组是[4,1,2,1,2]:

  • 初始:0 ^ 4 = 4
  • 4 ^ 1 = 5
  • 5 ^ 2 = 7
  • 7 ^ 1 = 6
  • 6 ^ 2 = 4(最终结果)

5. 三种解法的实测对比

在LeetCode判题系统测试(随机10万数据量):

解法运行时间内存消耗
哈希表28ms7.5MB
排序36ms7.2MB
位运算12ms6.5MB

实际工程中选择时还需考虑:如果数字范围极大(如64位整数),哈希表解法需要调整;如果内存极度受限,位运算是最佳选择。

6. 常见错误与调试技巧

6.1 哈希表越界问题

当数字为INT_MIN时,num + OFFSET可能下溢。防御性写法:

void insert(int num) { long index = (long)num + OFFSET; hash[index]++; }

6.2 排序解法的陷阱

未处理末尾元素的情况:

// 错误写法 for(int i = 0; i < numsSize; i += 2) { ... } // 当唯一数在末尾时会越界

6.3 位运算的扩展思考

如果题目改为"两个唯一数",解法会完全不同——需要先异或得到x^y,再根据某位差异分组异或。

7. 工程实践中的选择建议

  1. 嵌入式环境:优先位运算,避免动态内存分配
  2. 大数据处理:哈希表法可分布式扩展
  3. 已排序数据:直接线性扫描,无需预处理
  4. 面试场景:建议先给出哈希表解法,再优化到位运算

在C语言实际项目中,如果频繁需要哈希表,建议封装成泛型数据结构。这里给出一个简易模板:

typedef struct { int key; int val; } HashEntry; HashEntry* createHashTable(int size) { return (HashEntry*)calloc(size, sizeof(HashEntry)); } int hashFunc(int key, int size) { return (key % size + size) % size; // 处理负数 }

掌握这道题的多种解法,不仅能应对面试,更能培养对算法时空复杂度的敏感度。建议读者可以尝试用这三种方法解决LeetCode 137(数字出现两次,唯一数出现一次)和260(两个唯一数)的变种问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 10:17:42

2026年小说创作工具横评:AI辅助与专业写作软件对比

1. 为什么你需要这篇小说创作工具横评 去年我完成第一部30万字长篇时&#xff0c;用废了4款写作软件。从卡顿丢失章节的初代工具&#xff0c;到功能繁杂干扰创作的"全能选手"&#xff0c;最终在Scrivener上找回写作节奏。这段经历让我意识到&#xff1a;写作工具不是…

作者头像 李华
网站建设 2026/11/2 10:16:08

煤矿数字化转型:核心技术架构与实施策略

1. 煤矿信息化现状与发展趋势全景解读这份77页的PPT资料系统梳理了我国煤矿行业数字化转型的完整路径。作为在煤矿安全监控领域工作多年的技术负责人&#xff0c;我深刻体会到信息化建设对提升煤矿安全生产水平的关键作用。这份资料的价值在于它不仅呈现了当前技术应用现状&…

作者头像 李华
网站建设 2026/11/2 10:15:12

Paperclip详解:从文件上传到对象存储的完整实践指南

刚看到"paperclip"这个词&#xff0c;我第一反应倒不是什么代码仓库&#xff0c;而是办公桌上那枚平平无奇的回形针。一根钢丝弯三下&#xff0c;就能把散纸牢牢夹住&#xff0c;这个设计一百多年没大变过。而在Ruby on Rails的世界里&#xff0c;同样有一枚叫Paperc…

作者头像 李华
网站建设 2026/11/2 10:14:42

WinForm直传文件到Windows共享文件夹的SMB原生实现

简介&#xff1a;本资源是一个基于C# WinForm的局域网文件上传实践项目&#xff0c;面向Windows桌面应用开发者及企业内部系统初学者&#xff0c;解决WinForm程序中将本地文件安全、稳定上传至服务器共享文件夹的核心需求&#xff0c;适用于内网数据归集、办公文档同步等典型场…

作者头像 李华
网站建设 2026/11/2 10:13:54

基于EasyCVR的湿地公园智能监管系统设计与实践

1. 项目背景与需求分析 湿地公园作为城市生态系统中不可或缺的重要组成部分&#xff0c;其监管工作面临着诸多挑战。传统的人工巡查方式不仅效率低下&#xff0c;而且难以实现全天候、全方位的监控覆盖。我在参与某国家级湿地公园的智能化改造项目时&#xff0c;深刻体会到以下…

作者头像 李华
网站建设 2026/11/2 10:13:39

多语种数字人语音合成与唇形同步技术实践

1. 项目背景与核心价值 去年接触到一个外贸团队的效率优化需求&#xff0c;他们每天需要处理英、西、阿、日四种语言的客户沟通&#xff0c;传统人工录制视频存在三大痛点&#xff1a;多语种配音成本高、口型同步效果差、内容合规风险大。我们为其部署的矩阵跃动数字人系统&…

作者头像 李华