代码随想录算法训练营Day07||Leecode.454四数相加、Leecode.383赎金信、Leecode.15三数之和、Leecode.18四数之和

一、四数相加

        这题又是一道用map来解决的问题,本题的核心思路在于,把nums1,nums2两个数组看成一个整体,依次对他们进行遍历,并且把不同求和结果放到map里。其中,map的key值是两数之和,value是两数之和出现的次数。

        随后,再把nums3,nums4看成一个整体,这样把4个数组变成两个数组,转换成昨天做的两数之和的问题了。

        今天运用的map操作和昨天相比,今天采用了umap[a+b]++直接对相同key值进行value自增,相当于一个计数器,而昨天是用map来作为一个存储工具,用的是.insert({})添加键值对的方法。

        

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        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;
    }
};

 二、赎金信

       简单的数组哈希表,我的实现思路是,把magezine这个字符串先存起来,表示可用的字母数量,然后遍历ranstomNote数组,对哈希表内的次数进行递减,最后检查哈希数组,如果出现负数,就代表着有不够用的字母,返回false,否则就返回true

        

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int hash[1000]={0};
         for(int j=0;j<magazine.size();j++){
            hash[magazine[j]-'a']++;
        }
        for(int i=0;i<ransomNote.size();i++){
            hash[ransomNote[i]-'a']--;
        }
      
        for(int k=0;k<1000;k++){
            if(hash[k]<0)return false;
        }

        return true;
    }
};

三、三数之和

        这道题没有参考用哈希表的方法,用的是双指针。

        这题有一个知识点是,如果返回值需要返回下标,那么就不能进行排序操作,不需要返回下标值的话就可以排序后再做。

        本题涉及到了去重的操作,去重也分两种,一种是不与前面重复,一种是不与后面重复。在遍历下表i经过的元素时,采用的是不与前面重复,而后面在移动left和right指针去重的时候left是不与后面重复(left与left+1比较)right与right-1比较。

        本题的整体思路是:

        1.首先先将原数组排序,然后确定下标对应的元素值,再运用双指针看看能否找出来另外两个满足条件的数。

        2.在遍历数组元素的时候,如果首元素就大于0,那么后面的求和也一定大于0,直接跳出整个循环(break或return)。如果能够正常遍历,i>0的时候,再判断新遍历的元素和之前遍历过的元素是否重复,如果有重复跳出本次循环(continue)。

        3.在确定下标元素以后,双指针查值的时候,也要考虑去重的操作。这个去重操作要保证,left以后与left对应值相同的所有元素都要被覆盖过去,right之前所有的被覆盖。在写这一步while条件的时候,要先让left<right,再写其他条件,否则容易出现溢出的报错

        

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
     
     
     sort(nums.begin(),nums.end());
     int left,right;
     vector<vector<int>>result;

     for(int i=0;i<nums.size();i++){
        left=i+1;
        right=nums.size()-1;
        if(nums[i]>0)break;
        
      if(i>0&&nums[i]==nums[i-1]){
            continue;
        }
        while(left<right){
            if(nums[left]+nums[right]+nums[i]>0){
                right--;
            }
            else if(nums[left]+nums[right]+nums[i]<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;
    }
};

四、四数之和

        相较于三数之和,本题多加了一层循环遍历,同时意味着多一次去重剪枝的操作。

        

        第一次剪枝:让首元素保证不大于目标值,并且不能为负值,因为负数越加越小

        第一次去重:下标大于0,不与前重复

        第二次剪枝:让首元素(已经变成了两个元素相加)保证不大于目标值,并且不为负

        第二次去重:让j在i后一位,也就是让原来的i在0以后

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

                if(nums[j]+nums[i]>target&&target>0)break;
                if(j>i+1&&nums[j]==nums[j-1])continue;
                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{
                         while(left<right&&nums[left]==nums[left+1])left++;
                    while(left<right&&nums[right]==nums[right-1])right--;
                    result.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});

                    left++;
                    right--;

                    }
                }
               

            }
        }

        return result;
    }
};

        在其中测试的一组数据中,提示数据溢出,说明int类型不够存放,这里就涉及到了一个新的知识点,在前面加(long)进行转换

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值