代码随想录算法训练营第六天(哈希表 上)

第五天周日休息啦(没有day5)

哈希表理论基础

文章链接:代码随想录

 哈希表定义:哈希表是根据关键码的值(key)而直接进行访问的数据结构。

可能这样的定义有点笼统,简单来说就是一种快捷的便于查找的数据结构,比方说在数组里找一个元素,要遍历的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1)就可以做到。

本文主要围绕哈希表怎么使用展开,关于哈希表的原理就不解释了。

解题中主要用到的三种哈希结构(本文的下面力扣题会包含三种结构使用场景的题目):

  • 数组             (对应题号242)
  • set(集合)      (对应题号349,202)
  • map(映射)    (对应题号1)

数组就没什么可分类的了,主要是c++中set和map各有不同的三个结构可用:

集合底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::set红黑树有序O(log n)O(log n)
std::multiset红黑树有序O(logn)O(logn)
std::unordered_set哈希表无序O(1)O(1)

std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。

映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::map红黑树key有序key不可重复key不可修改O(logn)O(logn)
std::multimap红黑树key有序key可重复key不可修改O(log n)O(log n)
std::unordered_map哈希表key无序key不可重复key不可修改O(1)O(1)

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。

需要注意的点:

1.当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。(选择三种映射结构的map也是一个道理,看是否有序和重复选择)

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

3.使用哈希表就牺牲了空间换取了时间。

力扣题部分

242.有效的字母异位词

题目链接:. - 力扣(LeetCode)

思路(数组哈希表):

        s 和 t 仅包含小写字母,所以用数组开辟26个空间就行了,开辟后遍历字符串s,将每个元素的信息与0-25对应(a 对应 0, b 对应 1...)数组一开始都是0,每遍历一个元素就让对应元素在数组中+1,然后遍历字符串t,流程和遍历s差不多,把+1改成-1,都遍历后如果哈希表和原来一样,那就说明是异位词。

代码实现:

20bac93e34634612bec0e6e04509d5b8.png

349. 两个数组的交集

题目链接:. - 力扣(LeetCode)

思路(set哈希表):

        创建nums1的哈希表nums和空哈希表result,遍历nums2中的各个元素,如果元素在nums里有,也就代表在nums1里有相同值的元素。将其放进result里,遍历完后输出result。

代码实现:

4b73f81204364ad48726a88ca677f502.png

202. 快乐数

题目链接:. - 力扣(LeetCode)

思路(set哈希表):

        先将计算交给另一个函数cal,然后将每一次的结果记录到set中,如果结果是1好说,直接return true了,如果不是就要记录在哈希表set中,每次都要将结果查找一遍,如果有一样的就说明进入循环了,就可以 return false结束了。

代码实现:

4318a4a4201f45179be89c66c418f586.png        

思路(快慢指针):

        没想到吧,快慢指针他又来了!

        先和上面的思路差不多,构造计算的函数cal,然后就是判断是否循环了,和环形链表那道题一个逻辑,如果真的无限次到达不了1的话,一定会重复一样的数值,进入循环。如果一进入循环,也就能用快慢指针来探测是否为环状结构。具体操作的流程理解可以移步day4的环形链表II。(相信理解完这两道题你会感受到不一样的惊喜) 代码随想录算法训练营第四天| 24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,面试题 02.07. 链表相交,142.环形链表II,链表总结-CSDN博客

和环形链表题目不同的是,我们不需要知道具体在哪个点进入环,只用判断是否为环结构就可以了

代码实现: 

dc61629265d74adaa901261b0e17787d.png

1. 两数之和

题目链接:. - 力扣(LeetCode)

思路(暴力):

        像冒泡排序一样用双重for循环将所有的两两组合遍历一遍判断之和是否等于target。

代码实现:

893d747756e1477aa71c168b486e3682.png 

思路(map哈希表);

        用map的键代表元素值,用map的值代表元素下标,遍历nums,如果target - nums[i]在map中就直接return{iter->second,i} 。前者是map在target - nums[i]的值(也就是总和为target的对应nums[i]的另一个元素的下标),后者是i(当前遍历的元素下标)。如果没有对应值,那就把i 和 nums[i]记录到map中。遍历完后都没有找到,就return{}了。

代码实现:

f6cd1856eff845debe966f6aaf0001ec.png

 

 

 

  • 38
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值