第五天休息
哈希表理论基础
文章讲解:https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
常用的哈希结构有三种:数组、set、map
当遇到数据比较小的时候,就去用数组来哈希
遇到数据比较大的时候,用set
遇到有key值和value时,用map
下面是set和map常用的结构表格
总结一下,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
如果在做面试题目的时候,遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!
242.有效的字母异位词
题目链接:https://leetcode.cn/problems/valid-anagram/
文章讲解:https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
视频讲解:https://www.bilibili.com/video/BV1YG411p7BA
状态:不会哈希啊
思路
我们可以设置一个哈希数组,即设置一个数组用来存储26给英文字母出现的次序,然后比较第二个字符串,让每次的位置去减一即可
字符在数组的顺序怎么求?用字符的ASCII减去’a’就可
代码实现
class Solution {
public:
bool isAnagram(string s, string t) {
vector<int> hash (26,0);
for(int i = 0;i < s.size();i ++){
hash[s[i] - 'a'] ++;
}
for(int i = 0; i < t.size();i++){
hash[t[i] - 'a'] --;
}
for(int i = 0;i < 26;i ++){
if(hash[i] != 0){
return false;
}
}
return true;
}
};
359.两个数组的交集
题目链接:https://leetcode.cn/problems/intersection-of-two-arrays/
文章讲解:https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86.html
视频讲解:https://www.bilibili.com/video/BV1ba411S7wu
状态:用哈希数组做了出来
思路
自己看到题目的第一想法:
可类仿上一道题,创建一个hash数组去存第一个数组0-1000的数字不为零的情况,然后遍历第一个数组,去找hash数组中对应位置是否为零,若不为零,则为满足条件的元素。怎么去存储呢?我这里用了同样大小1000的数组去存,不为零的元素,然后再根据这个数组不为零的元素的长度去创造一个新数组,然后复制不为零的元素,输出
看完代码随想录之后的想法:
就我的用数组的思想,可以用set来存储结果,这样就不用去定义未知的长度了
但是这题正常来说该用我们说的set来做
补充一下Set.find的用法
如果找到元素,则返回指向该元素的迭代器,否则返回指向集合末尾的迭代器,即set :: end()。
代码实现
①数组
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> hash (1005, 0);
set<int> res;
for(int i = 0; i < nums1.size(); i++){
hash[nums1[i]] = 1;
}
for(int i = 0; i < nums2.size(); i++){
if(hash[nums2[i]] == 1){
res.insert(nums2[i]);
}
}
return vector<int>(res.begin(), res.end());
}
};
②set
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> nums_1 (nums1.begin(), nums1.end());
set<int> res;
for(int num:nums2){
if(nums_1.find(num)!= nums_1.end()){
res.insert(num);
}
}
return vector<int>(res.begin(), res.end());
}
};
202.快乐数
题目链接:https://leetcode.cn/problems/happy-number/
文章讲解:https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html
状态:没做出来
思路
自己看到题目的第一想法:
我觉得可以用递归去实现
看完代码随想录的想法:
当不是快乐数的时候,会陷入死循环中,即永远变不到1,sum会重复出现,即用一个set来存储sum,便于寻找,起始哈希用set主要就是用find函数
2.两数之和
题目链接:https://leetcode.cn/problems/two-sum/
文章讲解:https://programmercarl.com/0001.%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.html
视频讲解:https://www.bilibili.com/video/BV1aT41177mK
状态:不会
思路
用map去存储数组下标和元素值,然后遍历数组,对遍历的每个元素,去找找该数组下(也就是用map去找)有没有和该元素相加等于目标值的
我这两天在过寒假回家的路上,一路颠簸,今天傍晚终于到家了,看着进度有点落后,就来补补,剩最后两道题,实在熬不住了,先写下思路,明天代码
================================================================
补
202.快乐数
代码实现
class Solution {
public:
int getSum(int num){
int sum = 0;
while(num){
int n = num % 10;
sum = sum + n * n;
num = num / 10;
}
return sum;
}
bool isHappy(int n) {
int sum = 0;
unordered_set<int> set;
while(1){
sum = getSum(n);
if(sum == 1) return true;
if(set.find(sum) != set.end()){
return false;
}else{
set.insert(sum);
}
n = sum;
}
}
};
1.两数之和
思路补充
- 为什么用哈希?
答:当用查找一个元素是否重复出现过,或者一个元素或者在一个集合里出现过,用哈希。本体可以没查找一个元素,就去找找已经遍历过的元素有没有和它相加等于target值得 - 为什么用map?
答:本体既有元素值,又有下标 - 为什么用unordered_map?
答:unordered_map底层是哈希表实现的,便于查找 - map的作用是什么?
没遍历一个元素,就去查找已经遍历过的元素是否有和该元素相加等于target的元素,map就是用来存储遍历过的元素
代码实现
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> map;
for(int i = 0; i< nums.size(); i++){
auto iter = map.find(target - nums[i]);
if(iter == map.end()){
map.insert(pair<int, int>(nums[i], i));
}else{
return {iter -> second, i};
}
}
return {};
}
};
收获
当用查找一个元素是否重复出现过,或者一个元素或者在一个集合里出现过,用哈希。
哈希的核心就是查找是否出现过;
数组的查找核心就是hash(nums[i])是否为0
set和map的核心就是find函数的应用