力扣知识点--哈希表

1.理论基础

(1)含义

哈希表,又叫散列表,它是根据关键码的值而直接进行访问的数据结构。直白来说,其实数组就是一张哈希表,哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。一般哈希表都是用来快速判断一个元素是否出现在集合里,假如要查询一个名字是否在这所学校里,要枚举的话时间复杂度是O(N),但使用哈希表则只需O(1)。只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学是否在这所学校里。而将学生姓名映射到哈希表上就涉及到哈希函数。

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。

但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!

(2)哈希函数

哈希函数是把传入的key映射到符号表的索引上。它把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里了。

哈希函数通过hashCode把名字转化为数值,一般hashCode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这就可以把学生姓名映射到哈希表上的索引数字。

  • 如果hashCode得到的数值大于tableSize,此时为保证映射出来的索引数值都落在哈希表上,会再次对数值做一个取模的操作,就可保证姓名一定映射到哈希表上;
  • 如果学生数量大于tableSize,此时会出现几个学生姓名同时映射到哈希表同一个索引下标的位置,这个现象叫做哈希碰撞。

(3)哈希碰撞

哈希碰撞处理有多个key映射到相同索引上时的情景。小李和小王都映射到了索引下表 1的位置,这一现象叫做哈希碰撞。一般哈希碰撞有两种解决方法:拉链法和线性探测法。

  • 拉链法:

    刚刚小李和小王在索引1的位置发生了冲突,发生冲突的元素都被存储在链表中。 这样我们就可以通过索引找到小李和小王了

数据规模是dataSize,哈希表大小为tableSize。其实拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。

  • 线性探测法:

使用线性探测法,一定要保证tableSize大于dataSize。 我们需要依靠哈希表中的空位来解决碰撞问题。例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。所以要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放 冲突的数据了。如图所示:

(4)常见的三种哈希结构

当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构:

  • 数组
  • set(集合)
  • map(映射):key、value的数据结构,对key有限制,对value无限制。

2.经典题目

(1)数组作为哈希表

242.有效的字母异位词中,数组就是简单的哈希表,但是数组的大小是受限制的。在这道题目包含小写字母,那么使用数组来做哈希表最合适不过。(相关题目:383.赎金信、49.字母异位词分组、438.找到字符串中所有字母异位词

383.赎金信中同样要求只有小写字母。本题和242很像,242是求字符串a和字符串b是否可以相互组成,在383中是求字符串a能否组成字符串b,而不用管字符串b能不能组成字符串a。(相关题目:350.两个数组的交集II

以上两道题目均可使用map,但使用map的空间消耗要大于数组,因为map要维护红黑树或者符号表,而且还要做哈希函数的运算。

(2)set作为哈希表

349.两个数组的交集中数组的方法不可用,需用set来解决。本题没有限制数值的大小,就无法使用数组来做哈希表。

主要因为如下两点

  • 数组的大小是有限的,受到系统栈空间(不是数据结构的栈)的限制。
  • 如果数组空间够大,但哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。

所以此时一样的做映射的话,就可以使用set了。

(3)map作为哈希表

1.两数之和中map正式登场。

来说一说:使用数组和set来做哈希法的局限。

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下表位置,因为要返回x 和 y的下表。所以set 也不能用。

map是一种<key, value>的结构,本题可以用key保存数值,用value在保存数值所在的下表。所以使用map最为合适。

454.四数相加中我们提到了其实需要哈希的地方都能找到map的身影。本题咋眼一看好像和18. 四数之和15.三数之和差不多,其实差很多!关键差别是本题为四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑重复问题,而18. 四数之和15.三数之和是一个数组(集合)里找到和为0的组合,可就难很多了!用哈希法解决了两数之和,很多同学会感觉用哈希法也可以解决三数之和,四数之和。其实是可以解决,但是非常麻烦,需要去重导致代码效率很低。在15.三数之和中我给出了哈希法和双指针两个解法,大家就可以体会到,使用哈希法还是比较麻烦的。所以18. 四数之和,15.三数之和都推荐使用双指针法!

参考链接:https://github.com/youngyangyang04/leetcode-master

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值