一、 哈希函数
哈希函数:Hash(key)=key%TableSize
作用:把关键字 key 映射到哈希数组的下标
TableSize:哈希表长度,一般选质数,减少冲突
缺陷:不同 key 取模后得到相同下标 -> 哈希冲突
- 哈希冲突解决方式
1、开放寻址法
如果该下标已有元素,向后找空位存放;缺点:删除麻烦、容易聚集,简单题偶尔用。
2、拉链法(链地址法,最常用!)
哈希表每个位置是一条链表;发生冲突的元素直接挂在对应下标的链表上。
优点:增删简单、不容易堆积;手写哈希首选。
- 哈希集合 HashSet(逻辑概念)
功能:只保存元素,不保存对应数值,元素不可重。
适用场景:1、判断某个数是否存在
2、数组去重
C 语言实现方式:布尔数组 bool hash ,存在置 1,不存在置 0。
- 哈希映射 HashMap(键值对 key->value)
功能:保存key(关键字)和value(对应数据)
适用场景:统计元素出现次数、建立数值与下标、数值与次数的映射
C 语言实现:int 数组 hash\[\],hash key = 次数 / 对应值
重要限制:数组模拟哈希只适合 key 范围不大、非负数;
如果 key 存在负数、数值极大(如 1e9),只能手写拉链法链表哈希。
二、时间复杂度总结
理想无冲突:插入、查找、删除
冲突很多(链表很长):退化到
三、数组模拟哈希表使用规则
1、先预估数据范围,开辟足够大数组
2、负数处理:统一加上偏移量变成正数 key + offset
3、集合模拟:bool hN
存入:hkey=true
判断存在:if(hkey)
4、映射 / 计数模拟:int hN
计数:hkey++
获取次数:hkey
四、高频考点区分
1、哈希集合(bool 数组):只关心有没有
判断存在、去重
2、哈希映射(int 数组):关心对应的值 / 次数
统计频次、一一映射
五、易错重点
1、数组下标不能为负数!遇到负数 key 必须加偏移。
2、哈希表数组不要开太小,否则越界;全局数组放在静态区,空间更大。
3、多次测试用例,一定要清空哈希数组!memset 重置
4、取模运算表长尽量质数,减少冲突。
5、数组模拟哈希有数值范围限制;超大数必须链表实现。
题目一:理解:给一个整数数组 nums
如果数组有数字出现 >= 2 次 -> 返回 true
如果数组全部数字互不重复 -> 返回 false
关键点:只要求全局出现两次就行,不需要位置相邻。
思路:排序+相邻比较
1、将数组从小到大排序
2、排序完成后,相等的数字一定紧紧相邻
3、遍历数组,判断当前元素和下一个元素是否相等,相等返回 true

出现了错误:C 语言不允许在函数体内写#include,也不能在一个函数里面定义另一个函数(cmp
写在 containsDuplicate 里面属于嵌套函数,LeetC 编译器不支持),直接引发编译报错。
正确的:
1、qsort所需要的比较回调函数
2、强制转换成int指针,取出数值,实现从小到大排序

步骤一:调用qsort对数组升序排序
原始数组重复数字是分散的,无法简单判断。排序之后,相同的值一定会紧紧挨在一起。

步骤二:书写for循环,循环条件i < numsSize -1
依次取出数组每一个元素,准备和它后一位元素比较。
循环内部要访问numsi+1。假设数组一共 4 个元素,下标 0,1,2,3。

步骤3:if判断numsi == numi+1
检测当前位置和下一个位置数字是否相等。
经过排序,相等数字一定相邻。只要任意一种相邻数字相等,就证明数组存在重复元素。

步骤四:循环全部走完,执行return false
最终返回结果。
只有当整个循环完整跑完,全程没有找到任何一对相等的相邻元素,才能确定数组中不存在重复数字,此时返回false。

第二题:
思路:小写字母一共只有 26 个,我们开辟大小 26 的数组充当哈希表。
第一轮遍历字符串:统计每一个字符出现次数;
第二轮再次从头遍历字符串:按照原始顺序查找第一个出现次数等于 1的字符,直接返回它的下标;
两轮遍历结束没有找到,返回 - 1。
重点:必须两轮遍历。不能遍历哈希数组去找答案,会丢失字符串原本先后顺序!
步骤一:创建技术数组int cnt26 = 0;
充当哈希映射,存放26个小写字母出现次数,初始全部置0。
26个是因为题目字符串只有小写英文字母a~z,刚好26个。
映射规则:si - 'a' 把字符转为 0~25 的数组下标。

步骤二:第一轮for循环,统计字符出现次数
扫描一遍字符串,把每个字母出现多少次统计到哈希函数。
我们需要知道每个字符总共出现几次,才能判断是不是唯一字符。

步骤3:第二轮for循环,从头查找第一个次数 =1 的字符
按照字符串原始顺序遍历,找到第一个只出现一次的字符,返回下标。
cnt 数组是按 a-z 顺序存放,丢失字符串先后顺序。

步骤四:循环走完,执行return-1
所有字符出现次数都>=2,不存在唯一字符,按题目要求返回 - 1。
只有第二轮完整遍历结束,全程没有找到次数等于 1 的字符,才执行这条语句。