代码随想录训练营day05(哈希表)
242.有效的字母异位词
题目
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
解题方法(数组)
- 使用数组建立哈希关系
- key(数组下标):0~25,代表每个小写字母
- value(数组元素):小写字母出现的次数
- 把s的各字母次数存进数组
- 把t的各字母次数减掉
- 如果相减后的数组有格子不为0,说明s或t多/少了字母
难点(什么时候用数组)
- 为什么数组能看作简单的哈希表
下标充当key,而哈希表的核心是通过key快速找到value
- 什么情况用数组建立哈希关系
- 要查找某一元素,这个元素就要作为key。
- 数组下标充当key,数组内容充当value。
- 26个小写字母这种,少量且连续的数据,适合用数组。如果数据比较分散,考虑set和map。。
- 犯错:return的位置放在if对应的else里,导致没完成所有遍历就会return
代码
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26] = {0};
int i = 0;
//把s的各字母次数存进数组
for(i = 0; i < s.size(); i++){
record[s[i] - 'a']++;
}
//把t的各字母次数减掉
for(i = 0; i < t.size(); i++){
record[t[i] - 'a']--;
}
//如果相减后的数组有格子不为0,说明s或t多/少了字母
for(i = 0; i < 26; i++){
if(record[i] != 0){
return false;
}
}
return true;
}
};
349. 两个数组的交集
题目
给定两个数组 nums1 和 nums2 ,返回它们的交集 。输出结果中的每个元素一定是唯一的。我们可以不考虑输出结果的顺序 。
思考历程
数组1转换成set,数组2元素与set对比
解题方法(set)
- 为什么使用set
- 不用数组:哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费
- 不用map:本题只用到key,没用到value
- 使用unordered_set:结果要去重,对顺序没要求
- 解题流程
1、先将数组1转成set
2、把数组2的元素作为key,一一与set对比
3、如果有交集,就把交集的元素insert进结果set
难点(范围循环、匿名对象)
- 范围循环:用于遍历容器
for (int num : nums2) 循环遍历 nums2 中的每个元素,并把每个元素的值赋给num
- return匿名对象:
return vector<int>(result_set.begin(), result_set.end());
在函数中用于创建并返回一个临时的 vector,而不必在函数中为其分配变量名。一旦函数返回,这个匿名 vector 就会被销毁,因为它没有任何变量引用它。
如果你希望将结果的 vector 赋给一个具名变量,那么你可以在函数中创建一个变量,然后将结果赋给它,然后返回该变量,例如:
vector<int> result_vector(result_set.begin(), result_set.end());
return result_vector;
代码
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int>result_set;//接收结果的set,有去重功能
unordered_set<int>nums1_set(nums1.begin(),nums1.end());//nums1转成set,便于查找
for(int nums2_val:nums2){//范围循环,用于遍历容器
if(nums1_set.find(nums2_val) != nums1_set.end()){//找不到返回set.end()
result_set.insert(nums2_val);
}
}
return vector<int>(result_set.begin(),result_set.end());
}
};
202. 快乐数
题目
解题方法(set)
- 关键:sum重复出现,一定不是快乐数
- 流程:对于n计算sum,如果sum已在set中,说明已经进入循环,不可能是快乐数;否则添加sum进set并更新n
难点(想不到快乐数与否的判断点)
- 想不到突破点:sum重复出现,说明陷入了循环,一定不是快乐数
- 如何计算每个位置上的数字的平方和。
int get_sum(int n){
int sum = 0;//每次进来先清零
while(n){
sum += (n%10)*(n%10);//个位平方
n = n/10;//下一位变成个位
}
return sum;
}
- 犯错:没有写while(1)循环,这个死循环的意义是,一直迭代判断下去,有结果出现了才会退出循环,且循环条件不依赖sum或n。
- 犯错:更新sum没有放在循环里,要注意哪些计算是仅做一次,哪些计算是每轮必做的。
- 犯错:int get_sum()函数没有写返回值
代码
class Solution {
public:
int get_sum(int n){
int sum = 0;//每次进来先清零
while(n){
sum += (n%10)*(n%10);//个位平方
n = n/10;//下一位变成个位
}
return sum;
}
bool isHappy(int n) {
int sum = 0;
unordered_set<int>sum_set;
while(1){
sum = get_sum(n);
if(sum == 1){
return true;
}
if(sum_set.find(sum)!=sum_set.end()){//找到了重复的sum,说明已经开始循环
return false;
}
else{
sum_set.insert(sum);
}
n = sum;
}
}
};
1. 两数之和
题目
注意:返回下标!所以要用map
解题方法(map)
-
关键:key保存数值,value保存数值所在的下标
-
解法:在map中找是否有(target-num[i]),有的话返回两个下标,没有的话添加(数值,下标)进map中
难点(key和value分别存什么)
- 为什么会想到用哈希表:需要在数组中快速找到(target-num[i])
- 为什么用map不用set:题目要求返回数组下标(需要用到key-value结构)
- key和value分别存什么:目标数值是key(要找),该数值对应的下标是value
- 犯错:error: non-void function does not return a value in all control paths [-Werror,-Wreturn-type]}。编译器认为某些情况没有return,改正:在函数终止的大括号前加上return{}。
- 犯错:map的insert,需要用到对组 map_num.insert(pair<int,int>(nums[i], i));
代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int>map_num;//
for(int i=0; i<nums.size(); i++){
int find_num = target - nums[i];
auto iter = map_num.find(find_num);
if(iter != map_num.end()){//找到了
vector<int>v_result;
v_result.push_back(i);//当前下标
v_result.push_back(iter->second);//找到的下标
return v_result;
}
else{
map_num.insert(pair<int,int>(nums[i], i));//key为数值,value为下标
}
}
return {};
}
};