遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法.
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!
题目一
看到题目的第一想法:
比较字母是否相同,位置不同,能想到的是暴力解法.
看了代码随想录的想法:
1、选用合适的数据结构,数组,set,map?
- 题目有限制大小的用数组,比如这题的实际上是26个字母
- 如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费
2、通过字符串的字符和'a'对比,可以得到相对数值
[s[i] - 'a']
实现时的困难:
题目二
看到题目的第一想法:
题目中说到输出结果中的每个元素一定是 唯一 ,所以应该是要选用set
但是没太搞懂这个交集需不需要连着相交,看了一些题解,好想都只要求有元素相交就可以了, 没有一定要连着
看了代码随想录的想法:
- set数据结构优劣对比
std::set和std::multiset底层实现都是红黑树,std::unordered_set的底层实现是哈希表, 使用unordered_set 读写效率是最高的,并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set。
- 使用set的问题
直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。
题目三
看到题目的第一想法:
按照题目的方式推演了一下,先定义一个从0-9的平方和的map,如果取每位数字,再从map取平方值,相加,得到一个新数字,继续循环这个过程,只有当使用到的是0和1的,才能认为是快乐数(因为和为1,必然是n*0+1)应该是能解的.
但是这个n数字能非常大,要怎么取出其每位数字呢?这个就要另外用一个方法去取了.
看了代码随想录的想法:
代码随想录这里用了定义一个存储平方和sum的一个set,这个set应该不小.
有两个点:
- 需要熟悉取各个位的单数
- 有一个是否进入循环的判断,如果进入了循环,那肯定无法找到1,这个也是题目提示过的,这一点确实自己也没想到.
题目四
看到题目的第一想法:
题目提示可以假设每种输入只会对应一个答案.
感觉双指针也能做,但是复杂度不低,按照指针移动的步数来看的话;
既然这个题放在哈希法专题,那么可以从哈希法的角度考虑一下:
强调一下 什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
这里考虑到用set的话,要将nums进行set,然后遍历nums,set.find(target-nums[i]),存在的话就是可以算两数之和,但是题目要求返回的是下标,set可能不能满足.换成map会更好.
这里另外提一下,就是还得需要熟练set的各类操作.
看了代码随想录的想法:
再来看一下使用数组和set来做哈希法的局限。
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
- 这道题目中并不需要key有序,选择std::unordered_map 效率更高