18-哈希表/第 4 章 查找表相关问题(18题)


第 4 章 查找表相关问题(18题)

[toc]

查找,是使用计算机处理问题时的一个最基本的任务,因此也是面试中非常常见的一类问题。很多算法问题的本质,就是要能够高效查找。学会使用系统库中的 Map 和 Set ,就已经成功了一半。

4-1 查找问题简介(1题)

![image-20191123210759016](/Users/liwei/Library/Application Support/typora-user-images/image-20191123210759016.png)

例题1:LeetCode 第 349 题

题目要求:给定两个数组,写一个函数来计算它们的交集。例子:给定 num1= [1, 2, 2, 1], nums2 = [2, 2], 返回 [2]。提示:每个在结果中的元素必定是唯一的。我们可以不考虑输出结果的顺序。

题目难度:简单

中文网址:https://leetcode-cn.com/problems/intersection-of-two-arrays/description/

英文网址:

求解思路:

思路1(未实现):

思路关键:根据题意,我们很自然想到,逐个将数组 2 中的元素放到数组 1 中看看有没有,我们可以遍历查找,而二分查找是一个更好的选择。

思路的具体描述:因为使用二分查找算法要求数据是排好序的,因此首先对数组 1 排序,然后将数组 2 中的每个的元素依次到数组 1 中进行二分查找,如果查找到,就添加了结果集中。根据题目要求:“每个在结果中的元素必定是唯一的”,因此应该使用 Set 保存结果。

思路2(未实现):

思路关键:不妨两个数组都排序:

数组1:1,2,3,4,5

数组2:1,1,1,2,3

规则如下:依次把数组 2 中的元素拿出来,跟数组 1 最开头的那个元素进行比较,如果不相同,直接丢弃,如果相同,把这个数加入到结果集中,用 Set 保存,并且数组 1 中开头的这个元素也要拿掉。我这里说的拿掉的意思是,遍历的时候,两个数组的索引都 +1。

思路3(推荐):

思路关键:其实是我们更容易想到的算法,Set 不仅可以将结果去重,还可以帮我们进行查找。

思路的具体描述:首先将数组 1 全部放入 Set 中(因为题目要求每个在结果中的元素必定是唯一的,才可以这么做,例如 LeetCode 第 350 题就不能这么做了)。然后逐个将数组 2 中的元素检查在数组 1 中是否存在,使用 Set 的 contains 方法,如果存在就添加到最后的结果集中。

我的解答:https://gist.github.com/liweiwei1419/54f91cf8cce3d63c6c2e9bd0a18aee58

参考资料:

思考总结:

1、Set 是我们常用的数据结构,我们应该熟悉关于 Set 的常见的操作,以及关于 Set 的实现类的底层实现原理,例如 Java 语言中的 TreeSet 是红黑树实现(高级的平衡二分搜索树),HashSet 是散列表实现,熟悉理解了这些数据结构可以帮助我们高效解决问题。

4-2 map 的使用 Intersection of Two Arrays II(1题)

(完成)例题1:LeetCode 第 LeetCode 第 350 题。

题目要求:给定两个数组,写一个方法来计算它们的交集。例如:给定 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2]。注意:输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。我们可以不考虑输出结果的顺序。

![image-20191123210912376](/Users/liwei/Library/Application Support/typora-user-images/image-20191123210912376.png)

跟进:
(1)如果给定的数组已经排好序呢?你将如何优化你的算法?
(2)如果 nums1 的大小比 nums2 小很多,哪种方法更优?
(3)如果nums2的元素存储在磁盘上,内存是有限的,你不能一次加载所有的元素到内存中,你该怎么办?
题目难度:简单。
中文网址:https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/description/
英文网址:
求解思路:
思路1:对两个数组进行排序,遇到一样的元素,就添加到最后的结果集,应该使用 List 来保存。

可以使用题目给出的例子作为测试用例。

![image-20191123210946593](/Users/liwei/Library/Application Support/typora-user-images/image-20191123210946593.png)

思路2:使用 HashMap 就可以实现计算重复次数。
我的解答:https://gist.github.com/liweiwei1419/74ee4bc1d1443425ff6cc17df271a700
元素的出现的次数,就是我们须要关注的问题。这里提供一种 STL 为我们提供的容器的特性。

![image-20191123211038613](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211038613.png)

首先说明,上面的解法是正确的,但是我们要特别声明一下。在 C++ 中 map 是有默认值的:

![image-20191123211111563](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211111563.png)

如果我们想真正删除 C++ 中的 map,我们应该调用 map 的 erase 方法。

C++ 中的映射是有默认值的,并且在我们第 1 次访问 map 中的数据的时候,如果这个数据不存在,C++ 会帮我们插入到 map 中。这是 C++ 语言的特殊性。

下面我们摒弃 C++ 这种语言中关于 map 的特殊性,来做一种解法:

![image-20191123211131379](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211131379.png)

(1)第4-1节的问题

![image-20191123211213961](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211213961.png)

(2)第4-2节的问题

![image-20191123211231535](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211231535.png)

![image-20191123211242121](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211242121.png)

扩展:

![image-20191123211308235](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211308235.png)

数组的有序和查找问题通常是非常密切的,想到二分查找的思想。下一小节的时间性能如何?

4-3 Set 和 Map 不同底层实现的区别(5题)

![image-20191123211405812](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211405812.png)

![image-20191123211419782](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211419782.png)

![image-20191123211431398](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211431398.png)

![image-20191123211446726](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211446726.png)

二分搜索树可以做什么?

![image-20191123211509046](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211509046.png)

下面的改动虽然我们的改动非常小,但是在底层,我们使用了完全不同的数据结构,这样对时间复杂度有了很好的改进。

![image-20191123211607452](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211607452.png)

![image-20191123211626935](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211626935.png)

(完成)练习1:LeetCode 第 242 题 Valid Anagram

要求:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。

示例 1:输入: s = “anagram”, t = “nagaram”,输出: true。

示例 2:输入: s = “rat”, t = “car”,输出: false。

![image-20191123211827724](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211827724.png)

说明:你可以假设字符串只包含小写字母。

进阶:如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

题目难度:简单

中文网址:https://leetcode-cn.com/problems/valid-anagram/description/

英文网址:

求解关键:字母异位词的意思就是,字母还是这些字母,它们出现的次数也不变,唯一变化的是出现的次序。

思路1:

![image-20191123211852165](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211852165.png)

思路2:使用两个字符数组,代表 26 个字母,每个数位存储每个字母出现的次数。

![image-20191123211905734](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211905734.png)

看看用一个字符数组是不是也可以完成。

![image-20191123211923730](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211923730.png)

思路3:和思路 2 是一样的,只不过是使用 HashMap 完成包含各个字母数量的统计。

我的解答:https://gist.github.com/liweiwei1419/38506cfb10a64dadce4a50290ccfe915

思路4:Python 的写法,看一看就可以了。

![image-20191123211944645](/Users/liwei/Library/Application Support/typora-user-images/image-20191123211944645.png)

思路5: hash 的方法,不是很理解

![image-20191123212005742](/Users/liwei/Library/Application Support/typora-user-images/image-20191123212005742.png)

(未完成)练习2:LeetCode 第 202 题:Happy Number

题目要求:Happy Number。编写一个算法来判断一个数是不是“快乐数”。一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。

题目难度:简单

中文网址:https://leetcode-cn.com/problems/valid-anagram/description/

英文网址:

求解思路:将一个数到“它每个数位上的数的平方和”视为一个变换,则这个变换可以一直进行下去,直到变化的结果是 1 ,那么这个数就是“快乐数”。此时要注意了,如果在这个连续变换的过程中,中途变换的数字出现重复,则这个重复会循环出现,因此这个数就不是“快乐数”。那么检测这个变换中途的数字是否重复就可以使用 Set。

思考总结:很常规的一个问题,要多练习,特别要知道怎么样一步一步得到一个整数的每个数位上的数值。

(再做一遍)练习3:LeetCode 第 290 题 Word Pattern

题目要求:单词模式。给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循这种模式。这里的“遵循”指完全匹配,例如在pattern里的每个字母和字符串 str 中的每个非空单词存在双向单映射关系。例如:

pattern = “abba”, str = “dog cat cat dog”, 返回true.

pattern = “abba”, str = “dog cat cat fish”, 返回false.

pattern = “aaaa”, str = “dog cat cat dog” , 返回false.

pattern = “abba”, str = “dog dog dog dog” , 返回false.

说明:你可以假设 pattern str

![image-20191123212052935](/Users/liwei/Library/Application Support/typora-user-images/image-20191123212052935.png)

![image-20191123212115166](/Users/liwei/Library/Application Support/typora-user-images/image-20191123212115166.png)

题目难度:简单

中文网址:https://leetcode-cn.com/problems/word-pattern/description/

英文网址:

求解关键:题目要求的“双向单映射”即要求不同的字母不能映射到相同的单词,例如最后一个例子,就不符合要求。即已经出现过的单词,就不能再添加到字典中了,因此我们还需要一个集合来判断添加到字典中的单词是否重复。

练习4:LeetCode 第 205 题 Isomorphic Strings

题目要求:同构字符串。给定两个字符串 s 和 t,判断它们是否是同构的。如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。

题目难度:简单

中文网址:https://leetcode-cn.com/problems/isomorphic-strings/description/

英文网址:

求解关键:

我的解答:https://gist.github.com/liweiwei1419/83bdc86fbc76f77c8db32b05711e57a8

![image-20191123212244632](/Users/liwei/Library/Application Support/typora-user-images/image-20191123212244632.png)

(没有做完)练习5:LeetCode 第 451 题 Sort Characters By Frequency

题目要求:根据字符出现频率排序。给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

题目难度:中等。

中文网址:https://leetcode-cn.com/problems/sort-characters-by-frequency/description/

英文网址:

求解思路:这道题其实我们很容易能够想到做一次计数,即 counter 操作。但是在最后输出的时候,要按照出现的频率降序排列,这也难不倒我们,Java 中的 TreeSet 就是这样的数据结构,抽象地说,利用二分搜索树的顺序性,可以帮助我们完成对放入“集合”(这里是抽象的集合,不是针对这道问题的集合)中的元素的排序工作。

3 种排序思路:

(1)使用字符串排序,指定排序规则;

(2)使用 TreeSet(也要指定排序规则);

(3)使用优先队列(最大堆,同样要指定排序规则)。

使用排序,给出排序规则。或者优先队列。

![image-20191123212336678](/Users/liwei/Library/Application Support/typora-user-images/image-20191123212336678.png)

![image-20191123212347190](/Users/liwei/Library/Application Support/typora-user-images/image-20191123212347190.png)


文章作者: liweiwei1419
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 liweiwei1419 !
评论
 上一篇
18-哈希表/第 4 章第 4 节《使用查找表的经典问题 Two Sum》(4题) 18-哈希表/第 4 章第 4 节《使用查找表的经典问题 Two Sum》(4题)
4-4 使用查找表的经典问题 Two Sum(4题)[TOC] 例题1:LeetCode 第 1 题题目要求:两数之和。给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用
2019-11-23 liweiwei1419
下一篇 
09-queue/0630-course-schedule-iii 09-queue/0630-course-schedule-iii
「力扣」第 630 题:课程表 III 链接:https://leetcode-cn.com/problems/course-schedule-iii 这里有 n 门不同的在线课程,他们按从 1 到 n 编号。每一门课程有一定的持续上课
2019-11-23 liweiwei1419
  目录