代码随想录算法训练营第七天 | 454.四数相加II , 383. 赎金信 , 15. 三数之和 , 18. 四数之和 , 总结

Day07

454 .四数相加II

一开始还是没思路,知道是哈希的应用,

思路如下:首先是4个数的哈希肯定没法用,已知两数之和可以找,所以两两分组,将a+b放在map中,然后通过遍历c+d,看0-(c+d)在没在map中,如果在,就说明可以相加为0。

次数计算的逻辑:首先将map的vlaue中存放可能得到a+b的和的次数。然后由于c+d是直接遍历的,所以每存在一个a+b,直接将value累加就好了。

重点:对于一个map,如果在map的key中存在i      则map[i]返回的是这个位置的value值。

如果不存在,则将i插入,然后将value初始化为0;

本题中的map[a+b]++就是将a+b这个key的value值自加1.

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        std::unordered_map<int,int> umap;
        for(int a:nums1){
            for(int b:nums2){
                umap[a+b]++;
            }
        }
        int count=0;
        for(int c:nums3){
            for(int d:nums4){
                if(umap.find(0-(c+d))!=umap.end()){
                    count+=umap[0-(c+d)];
                }
            }
        }
        return count;
    }
};

383. 赎金信

第一时间想到用map解决,

思路:首先将magazine的字符放入map中,然后使用ransomNote进行比对(哈希表),条件:没找到或者该字符value的值为负(也就是magazine中不够用),就输出false。

重点:这里使用的字符要用char,而不是string,       map中可以使用的数据类型很多,复合数据类型也可以,包括自定义结构体或类等,  比如std::pair<int, int> 作为键类型

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        std::unordered_map<char,int> umap;
        for(int i=0; i<magazine.length();i++){
            umap[magazine[i]]++;
        }
        for(int i=0;i<ransomNote.length();i++){
            if(umap.find(ransomNote[i])==umap.end()){
                return false;
            }
            else{
                umap[ransomNote[i]]--;
            }
            if(umap[ransomNote[i]]<0){
                return false;
            }
        }
        return true;

    }
};

本题因为是有限的数据,只要存储26个字符(使用数组来做哈希的题目,是因为题目都限制了数值的大小。

小tips:magazine.size()与magazine.length() 没有区别,可互换,都是返回字符串长度。

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26]={0};
        if(ransomNote.size()>magazine.size()){
            return false;
        }
        for(int i=0;i<magazine.length();i++){
            record[magazine[i]-'a']++;
        }
        for(int i=0;i<ransomNote.length();i++){
            record[ransomNote[i]-'a']--;
            if(record[ransomNote[i]-'a']<0){
                return false;
            }
        }
        return true;
    }
};

5. 三数之和

有时间看下哈希

本题用双指针,因为去重好考虑。

在对数组排序后,可能重复的就只有a与b之间,b与c之间 ,首先a的重复:a前后一个值,然后b与c与上面值一样,比如-1,-1,0,1。a移动,但是bc不动,还是-1 0 1。

b与c的重复,在找到一组值之后,移动前后b与c的值不变。-2  -1 -1  3 3,都是-2 -1 3。

上面的处理都是找到下一个变化的值。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();i++){
            if(nums[i]>0){
                return result;
            }
            if(i>0 && nums[i-1]==nums[i]){
                continue;
            }
            int left = i+1;
            int right = nums.size()-1;
            while(left<right){
                if(nums[i]+nums[left]+nums[right]>0) right--;
                else if(nums[i]+nums[left]+nums[right]<0) left++;
                else{
                    result.push_back(vector<int>{nums[i],nums[left],nums[right]});
                    while(left<right && nums[left]==nums[left+1]){ left++;}
                    while(left<right && nums[right]==nums[right-1]){ right--;}
                    left++;
                    right--;
                }
            }
        }
        return result;
    }
};

18. 四数之和 

这个就是三数之和外面再加上个for循环,其次需要注意的就是第二层循环的判断条件。

对于第二层for循环的去重条件,这里要写成j>i+1的形式,这个去重的前面j的范围不仅仅是保证前面是存在数的(这个是三数求和 for循环去重条件为什么要写成 i >0),还要保证 j 的第一次循环可以进行下去。举例:[2,2,2,2,2] target=8.

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();i++){
            if(nums[i]>target && nums[i]>0){
                break;
            }
            if(i>0 && nums[i]==nums[i-1]){
                continue;
            }
            for(int j=i+1;j<nums.size();j++){
                if(nums[j]+nums[i]>target && nums[j]+nums[i]>0){
                    break;
                }
                if(j>i+1 && nums[j]==nums[j-1]){
                    continue;
                }
                int left=j+1;
                int right=nums.size()-1;
                while(left<right){
                    if((long)nums[i]+nums[j]+nums[left]+nums[right]>target) right--;
                    else if((long)nums[i]+nums[j]+nums[left]+nums[right]<target) left++;
                    else{
                        result.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});
                        while(left<right && nums[left]==nums[left+1]) left++;
                        while(left<right && nums[right]==nums[right-1]) right--;
                        left++;
                        right--;                    
                    }
                }
            }
        }
        return result;
    }
};

总结

哈希表的作用:用于快速查找数据,分为数组,set和map,数组一般用于数组可能得情况有限(一般是26英文字母这种),set是只用一个key值就可以,map是有key和value两个。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值