本系列总计六篇文章,是 基于STL实现的笔试题常考七大基本数据结构 该文章在《代码随想录》和《labuladong的算法笔记》题目中的具体实践,每篇的布局是这样的:开头是该数据结构的总结,然后是在不同场景的应用,以及不同的算法技巧。本文是系列第三篇,介绍了哈希表的相关题目,重点是要掌握STL的set和map,注意N数之和问题,用双指针最方便。
下面文章是在《代码随想录》和《labuladong的算法笔记》题目中的具体实践:
【笔记】数组
【笔记】链表
【笔记】哈希表
【笔记】字符串
【笔记】栈与队列
【笔记】二叉树
0、总结
-
哈希表用来快速判断一个元素是否出现在集合里
-
一般常用数组、
unordered_set
、unordered_map
这三种数据结构实现哈希表,后两者的底层实现是哈希表,无序、数值(key)不可重复、数值(key)不可修改、查询和增删效率都是 O(1) -
set,multiset,map,multimap底层是红黑树,当要求key有序、重复时,可以选用
-
两数、三数、四数之和问题,用 双指针法 最方便
1、set 作为哈希表
349. 两个数组的交集 - 力扣(LeetCode)
思路:输出交集,要求去重、不考虑输出结果的顺序,因此选用unordered_set
注意:set和vector互相转化可以用构造函数直接实现,不需要遍历;set增加元素用insert;用auto更方便
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> result;
// 要去重,所以用unordered_set
unordered_set<int> result_set, nums1_set;
// unordered_set<int> nums_set(nums1.begin(), nums1.end());
for (int i : nums1)
nums1_set.insert(i);
for (int i : nums2) {
if (nums1_set.find(i) != nums1_set.end()) {
result_set.insert(i);
}
}
// return vector<int>(result_set.begin(), result_set.end());
for (auto it = result_set.begin(); it != result_set.end(); it++)
result.push_back(*it);
return result;
}
};
202. 快乐数 - 力扣(LeetCode)
思路:用set判断集合中的某个元素是否出现过,若出现过,代表有循环,此数并非快乐数,应及时return
注意:按位取数的写法应牢记,n不为0的情况下,不断地先%10,再/10,这样可以低位到高位取数
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> set;
while(1) {
int sum = getSum(n);
if (sum == 1) return true;
if (set.find(sum) != set.end()) {
return false;
} else {
set.insert(sum);
}
n = sum;
}
}
int getSum(int n) {
int sum = 0;
while (n) {
sum += pow(n % 10, 2);
n /= 10;
}
return sum;
}
};
2、map 作为哈希表
350. 两个数组的交集 II - 力扣(LeetCode)
思路:与349的区别是,不去重,若公共元素是a,返回结果中a出现的次数,应与a在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值),要用unordered_map
进阶:
-
如果给定的数组已经排好序呢?你将如何优化你的算法?用双指针只需 O(n) 的时间复杂度
-
如果 nums1 的大小比 nums2 小,哪种方法更优?较小的数组用hash存储,然后在另一个数组中寻找
-
如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
还是较小的数组用hash存储,然后在另一个数组中,每次读取出一部分数据进行寻找
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
vector<int> result;
// 题目不要求去重
unordered_map<int, int> map;
for (int i : nums1)
map[i]++;
for (int i : nums2) {