文章链接:哈希表理论基础242.有效的字母异位词349. 两个数组的交集202.快乐数1.两数之和

视频链接:242.有效的字母异位词349. 两个数组的交集1.两数之和

题目链接:242.有效的字母异位词349. 两个数组的交集202.快乐数1.两数之和


哈希表理论基础

代码随想录算法训练营第五天| 242.有效的字母异位词、349. 两个数组的交集、202.快乐数、1.两数之和_i++

清晰版本请挪步幕布链接:哈希表理论基础思维导图

思路

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集合中是否存在元素numstd::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个半小时,因为昨天刚从学校搬东西到家,所以没写,今天补上。