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

目录

242.有效的字母异位词

 前言:

算法实现:

算法分析:

349. 两个数组的交集

前言:

方法一:暴力解法

方法二:哈希表

第一种:利用集合set实现:

第二种:利用数组实现:

第202题. 快乐数

 前言:

算法实现:

1. 两数之和

 前言:

方法一:暴力解法

方法二:哈希表(map实现)

总结: 


242.有效的字母异位词

题目链接

文章链接

 前言:

        本题要求判断两个字符串是否有相同的字符组成,且构成的每个字符数也要相等,第一个条件很好实现,主要还要在于结合第二个条件。首先想到的是两个for循环构成的暴力解法,但是想了好久也一直无法实现全部案例通过,这里就只展示哈希表方式实现的算法了。

算法实现:

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

算法分析:

        本题算法通过哈希表中的数组实现,用数组存放字符串中26个字母出现的次数,统计出第一个字符串组成字符的数目后减去第二个字符串的组成字符,若最后数组元素全部归零,则两字符串是有效的字母异位词,反之则不是。

        本算法的巧妙之处在于利用nums[s[i] - 'a']++、nums[t[j] - 'a']--实现统计数组的增减,s[i] - 'a' 可以将通过字符之间的ASCII码计算得到对应的0-25数字。

349. 两个数组的交集

题目链接

文章链接

前言:

        与上一题类似,不仅要考虑两数组是否存在相同元素,还要考虑元素的唯一性,本题分别利用暴力解法和哈希表进行实现,并且分别利用哈希表中的数组和集合set进行实现。

方法一:暴力解法

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> result;
        int num[1000] = {0};
        for (int i = 0; i < nums1.size(); i++){
            for (int j = 0; j < nums2.size(); j++){
                if (nums1[i] == nums2[j] && num[nums1[i]] == 0){
                    result.push_back(nums1[i]);
                    num[nums1[i]]++;
                }
                
            }
        }
        return result;
    }
};

        暴力解法主要依靠两个for循环实现,先创建一个vector容器进行相交非重复数组的存放,利用一个容量为1000的数组(容量根据nums1/nums2的最大长度确定)进行相交数值的重复性检验,num数组元素的值若为0则表示还未有当前大小重复值出现,若为1则已出现并记录,下次出现不再存放入vector容器中。

方法二:哈希表

        在选择数组或集合做哈希表时要注意合适的应用场合,例如使用数字做哈希表需要题目限制数值的大小如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。本题设置了数组元素数值大小,数组和集合作为哈希表皆可。

        在选择数组、集合或映射作为哈希表时,如果目的没有要求有序,可以采取unordered_的形式,其读写效率最高,并且可以实现不能重复。

第一种:利用集合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 n : nums2){
            if (nums_set.find(n) != nums_set.end()){
                result_set.insert(n);
            }
        }
        return vector<int> (result_set.begin(), result_set.end()); //匿名对象
    }
};

        本算法主要复习find()函数的用法:C++中find在容器中找到值是返回迭代器,找不到就返回迭代器end()。创建两个集合,一个作为最终存放结果的容器,另一个接受nums1的全部元素,再依次遍历nums2中所有元素,查找是否在容器中有该值,若存在则存放入第一个容器中。最终返回时还要将set转换为vector的格式。

第二种:利用数组实现:
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set;
        int hash[1002] = {0};
        for (int num : nums1){
            hash[num] = 1;
        } 
        for (int num : nums2){
            if (hash[num] == 1){
                result_set.insert(num);
            }
        }
        return vector<int> (result_set.begin(), result_set.end());
    }
};

        创建一个存放交集的集合和一个存放重复值出现次数的哈希数组(若重复值已出现过,数组中记录为1,否则为0),实现存放入集合的数据都不是重复的。最终返回时同样要将set集合转化为vector。

第202题. 快乐数

题目链接

文章链接

 前言:

        根据题目描述可知,数字每个位置的平方和相加有两种情况:第一种每个位置上数的平方和sum相加后等于1,;第二种是sum的值始终不为1,且最终陷入无限循环中。

        无限循环是一个切入点,我们可以利用哈希表记录每次平方求和得到的值,并判断当前要存入的值是否已经存入,若已存入那么证明sum已经陷入无限循环之中,可以确定该数不是快乐数。下面是具体的算法实现。

算法实现:

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;
            }
            if (set.find(sum) != set.end()){
                return false;
            }
            set.insert(sum);
            n = sum;
        }
        return{};
    }
};

算法分析:

        首先定义了一个对数值各部分平方求和的函数,方便在判断函数中的循环内直接调用,在判断函数中先定义存放sum的集合set,方便在循环中直接利用find查找集合中是否存在当前sum值。不存在则加入该sum,存在证明陷入无限循环,返回false,若sum的值为1可以直接返回true,在每次将sum存入集合后还要更新n值。

1. 两数之和

题目链接

文章链接

 前言:

        题目要求我们查找到和为某值的两数并返回他们的下表,最先想到的是利用暴力的解法两个for循环遍历,找到符合条件的两值时将它们的下表存放入vector中并返回。还可以利用哈希表实现,将查找和为某数target的两数转变为在哈希表中寻找target-其中一数的形式,由于要返回对应下表且没有顺序要求,可以使用unordered_map实现。

方法一:暴力解法

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> result;
        for (int i = 0; i < nums.size(); i++){
            for (int j = 0; j < nums.size(); j++){
                if ( i != j && nums[i] + nums[j] == target){
                    result.push_back(i);
                    result.push_back(j);
                    return result;
                }
            }
        }
        return{};
    }
};

        暴力解法的实现思路很清晰,不再过多介绍。

方法二:哈希表(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()){
                return {iter->second, i}; //iter->second是另一个数的下标,i是当前数的下标
            }
            map.insert(pair<int, int>(nums[i], i));
        }
        return {};
    }
};

        由于哈希表map中要存放value和key两个值,需要注意map的创建和插入数组时相对于set的不同点,循环内创建的iter的自动变量类型auto会与等号后的内容相同,此时iter是一个迭代器类型,iter指向的第一个元素first是target - nums[i]的值,即对应map中的key,指向的第二个元素second是target - nums[i] 值对应的下标,即对应map中的。

总结: 

        今天主要针对哈希表做了一些针对性的练习,对于哈希表的不同形式数组、set、map都有了初步的接触,并且对于不同场合下使用那种哈希表结构也有了一定的了解。

  • 35
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值