Day06|哈希表01:242.有效的字母异位词、349. 两个数组的交集、202.快乐数、1.两数之和

242.有效的字母异位词

leetcode链接:力扣题目链接(opens new window)

视频链接:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词(opens new window)‘

这题一刷就可以AC了,主要思路就是通过hashtable记录每个字符串的每个字符的出现次数,最后两次遍历后为0说明两个句子符合要求。注意点有三:

  • 可用数组创建hashtable,其中key是小写字母本身,value是出现次数(int)
  • 创建索引是key应该是[c - ‘a’],否则数组会越界;
  • 可用
for (int count: record) {进行数组的遍历

题解:

class Solution {
public:
    bool isAnagram(string s, string t) {
        int alphabet[26] = {0};
        for(int i = 0; i < s.length(); i++){
            alphabet[s[i] - 'a']++;
        }
        for(int j = 0; j < t.length(); j++){
            alphabet[t[j] - 'a']--;
        }
        for(int k = 0; k < 26; k++){
            if(alphabet[k] != 0){
                return false;
            }
        }
        return true;

    }
};

349. 两个数组的交集

leetcode链接:力扣题目链接(opens new window)

视频链接:学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集 (opens new window)

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

这题是二刷,直接有思路了。本来的思路跟第一题一样,使用unordered_map遍历nums1的时候记录下每个元素出现的次数,遍历nums2的时候查表,只要次数大于0,说明重复,加入结果res数组中。但是最后没有AC,这是因为res中元素可能是重复的。

因此需要使用set存储最后的结果,再转化为vector,最后修改后AC了,我的代码如下:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int> table;
        set<int> res;
        for(int num : nums1){
            table[num]++;
        }
        for(int num : nums2){
            if(table[num] > 0){
                res.insert(num);
            }
        }
        vector<int> res1(res.begin(),res.end());//使用迭代器构建vector。
        return res1;
    }

这里注意从set->vector的转化方式:

vector<int> res1(res.begin(),res.end());//使用迭代器构建vector。

然后查看题解后,发现其实并不需要unordered_map,使用unordered_set对nums1进行去重再在nums2中进行查找即可:

public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
        unordered_set<int> nums_set(nums1.begin(), nums1.end());
        for (int num : nums2) {
            // 发现nums2的元素 在nums_set里又出现过
            if (nums_set.find(num) != nums_set.end()) {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};
  

这里注意if (nums_set.find(num) != nums_set.end()) { 函数,set.find()函数返回对应的迭代器,如果找不到返回end()。然后set的操作使用insert进行插入。

快乐数

leetcode链接:力扣题目链接(opens new window)

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
  

这道题是一刷,看到的第一眼以为是个数学问题,没想过怎么用hashtable做,后来看题解才明白,可以用unordered_set存放sum的值,每次sum只要重复了说明会重蹈复辙,肯定不是快乐数,然后再找使最后的sum为1设为循环结束的条件即可。看完直接写代码然后AC了:

class Solution {
public:
    long getSum(int n){//得到各位的平方和
        int sum = 0;
        do{
            sum += (n % 10) * (n % 10);
            n = n / 10;
        }while(n > 0);
        return sum;
    }
    bool isHappy(int n) {
        //关键点在于判断sum是否重复出现,否则就会重蹈覆辙;
        unordered_set<int> sums;
        int sum = getSum(n);
        while(sum != 1){
            cout << sum << endl;
            if(sums.find(sum) != sums.end()){
                return false;
            }
            sums.insert(sum);
            sum = getSum(sum);
        }
        return true;
    }
};

这里需要注意的是getSum()函数,求每一位然后分别求平方,可以分离出来先调试正确。

标准题解:

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) {
        unordered_set<int> set;
        while(1) {
            int sum = getSum(n);
            if (sum == 1) {
                return true;
            }
            // 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
            if (set.find(sum) != set.end()) {
                return false;
            } else {
                set.insert(sum);
            }
            n = sum;
        }
    }
};

整体比我写的更连贯,都在while循环中做了。

  1. 两数之和

leetcode链接:力扣题目链接(opens new window)

视频链接:梦开始的地方,Leetcode:1.两数之和 (opens new window)

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9

所以返回 [0, 1]

好几次刷leetcode都止步于此。。。首先暴力解法肯定是能想到的,每遍历一个元素,都在数组中搜target - n在不在数组中,在就直接返回。可是这题安排在hashtable章节,肯定是能用hash表解决。这题之前刷过,但是思路不是很清晰,后来才想到可以使用unordered_map把之前出现的存起来。其中key是值,value是对应的下标:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> table;//key为值,value为下标
        for(int i = 0; i < nums.size(); i++){
            auto iter = table.find(target - nums[i]);
            if(iter != table.end()){
                return {iter->second,i};
            }else{
                table[nums[i]] = i;
            }
        }
        return {0,0};
    }
};

标准题解:

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++) {
            // 遍历当前元素,并在map中寻找是否有匹配的key
            auto iter = map.find(target - nums[i]); 
            if(iter != map.end()) {
                return {iter->second, i};
            }
            // 如果没找到匹配对,就把访问过的元素和下标加入到map中
            map.insert(pair<int, int>(nums[i], i)); 
        }
        return {};
    }
};

可以看到插入两个方法都可以,insert和直接赋值。

总结

hashtable部分的题都不算难,对我比较重要的是C++中set和map的用法,创建、插入什么的,过了一个充实的周一。

你可能感兴趣的:(散列表,数据结构)