文章链接:哈希表理论基础、242.有效的字母异位词、349. 两个数组的交集、202.快乐数、1.两数之和
视频链接:242.有效的字母异位词、349. 两个数组的交集、1.两数之和
题目链接:242.有效的字母异位词、349. 两个数组的交集、202.快乐数、1.两数之和
哈希表理论基础
清晰版本请挪步幕布链接:哈希表理论基础思维导图
思路
242.有效的字母异位词
这道题用哈希表的思路如下,先将s中的每个字符映射为一个数组的下标,然后字符的大小为数组的元素(桶排序)。然后对t也是同样的操作,不一样的是减去字符的大小。最后,若该数组元素全为0,那么符合题意,若出现有不为0的数,那么就不符合题意。
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26] = {0};
for(int i = 0; i < s.size(); i++){
record[s[i] - 'a']++;
}
for(int i = 0; i < t.size(); i++){
record[t[i] - 'a']--;
}
for(int i = 0; i < 26; i++){
// 若该数组元素全为0,那么符合题意,若出现有不为0的数,那么就不符合题意
if(record[i] != 0)
return false;
}
return true;
}
};
349.两个数组的交集
因为需要去重,所以考虑用哈希结构set,其中unorder_set最为合适。思路如下,先将nums1的数放入一个集合nums_set中,再遍历nums2,看能否.find到nums_set中的其中一个元素。有则将这个数insert到result_set集合中,最后返回result_set。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set;
unordered_set<int> nums_set(nums1.begin(), nums1.end());
for(int num : nums2){
if(nums_set.find(num) != nums_set.end()){
// 即nums2中有这个数
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};
202.快乐数
判断该数是不是“快乐数”,就是判断是否进入了循环。而判断是否进入了循环,就是判断当前的sun是否在之前出现过。而判断一个数是否出现过或者说一个数是否出现在集合中,就要考虑到用哈希表。
class Solution {
public:
// 定义一个函数计算每个位置上的数字的平方和
int getSum(int n){
int sum = 0;
while(n){
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
bool isHappy(int n) {
std::unordered_set<int> set;
while(1){
int sum = getSum(n);
if(sum == 1){
return true;
}
if(set.find(sum) != set.end()){ // 表示sum曾经出现过,表明进入了循环,即不是“快乐数”。
return false;
}else{
set.insert(sum);
}
n = sum; // 更新n
}
}
};
1.两数之和
因为遍历到一个元素num后,就要查找target-num是否出现过,所以考虑到用哈希表求解。又因为要存储两种元素(数值和下标),所以只能用map。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map<int, int> map;
for(int i = 0; i < nums.size(); i++){
auto iter = map.find(target - nums[i]);
if(iter != map.end()){
return {iter->second,i};
}
map.insert(pair<int, int>(nums[i], i)); // 第一个值是元素,第二值是下标
}
return {};
}
};
困难
242.有效的字母异位词
无
349.两个数组的交集
问:为什么会考虑到用unorder_set这个哈希结构?
答:因为unorder_set的底层实现是哈希表,效率最高;其他两个的底层实现是红黑树,所以查找比较麻烦。
问:for(int num : nums2)是什么意思?
答:相当于如下代码
int num;
for(int i=0;i<nums2.size();i++){
num=nums2[i];
}
大致意思就是遍历nums2中的每个元素,给遍历到的元素取名为num。
问:为什么” if(nums_set.find(num) != nums_set.end())“能表示判断nums2中是否有这个数?
答:这行代码用于检查nums_set
集合中是否存在元素num
。std::unordered_set::find()
函数返回一个迭代器,指向元素在集合中的位置。如果元素不存在,则返回集合的末尾迭代器std::unordered_set::end()
。
注意:集合的末尾迭代器即end()并不是返回集合的最后元素,而是最后一个元素后面的迭代器。
问:为什么最后是 return vector<int>(result_set.begin(), result_set.end()) , 为不是直接return
result_set?
答:是强制类型转换,为了符合函数的返回类型。
return vector<int>(result_set.begin(), result_set.end())
是一种强制类型转换的语法形式。在这里,它将 result_set
中的元素转换为 vector<int>
类型,并将其作为函数的返回值返回。
result_set.begin()
和 result_set.end()
是迭代器,分别表示 result_set
容器中第一个元素和最后一个元素之后的位置。通过将迭代器范围传递给 vector<int>
的构造函数,可以将 result_set
中的元素复制到一个新的 vector<int>
对象中。
这种方式可以方便地将 unordered_set<int>
转换为 vector<int>
,以符合函数的返回类型。
202.快乐数
无
1.两数之和
问:auto是什么?
答:auto是一个占位符,原理是根据值推测其类型。其作用是为了简化变量初始化。
注意:
1.用auto声明的变量必须初始化(auto是根据后面的值来推测这个变量的类型,如果后面没有值,自然会报错);
2.函数和模板参数不能被声明为auto(原因同上);
3.因为auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作,如sizeof和typeid;
4.定义在一个auto序列的变量必须始终推导成同一类型;
问:iter->second是什么意思?
答:iter->first 表示的是这个元素的key的值;iter->second 表示的是这个元素的value的值。
问:return{} 表示的是什么?
答:这时C++11的语法。表示“返回一个用空列表初始化器初始化的函数返回类型的对象,确切的行为取决于返回对象的类型。可用于返回多个数值,如上 return {iter->second,i} 。
今日收获
这部分大概用了2个半小时,因为昨天刚从学校搬东西到家,所以没写,今天补上。