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

文章介绍了如何使用双指针法和unordered_map数据结构解决编程问题,包括四数之和(454题)和三数之和(15题)的高效算法,以及赎金信问题(383题)的两种解法,强调了在处理这类问题时的空间和时间复杂度优化策略。
摘要由CSDN通过智能技术生成

一、454. 四数相加 II

题目链接:454四数之和

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { 
//1、四层for循环时间复杂度高
//利用空间换取时间,将a+b的结果的数量通过map存放起来,再通过一步步查找出-(c+d)的个数
        std::unordered_map<int, int> cnt;
//a+b+c+d = 0
//--->a+b = -(c+d);
        for(auto a:nums1){
            for(auto b:nums2){
                cnt[a+b]++;
            }
        }
        int res = 0;
        for(auto c:nums3){
            for(auto d:nums4){
                res+=cnt[-(c+d)];
            }
        }   
        return res;
    }
};

二、383. 赎金信

题目链接:383
自己写的第一种解法:

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

第二种解法:

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;
    }
};

三、15. 三数之和

题目链接:15
思路:找到a+b+c = 0的元组,通过双指针法,先固定a,再移动b和c,b代表排序后比a大的第一个位置的值,c是最后一位,然后不断的缩小[b,c]边界,值到a+b+c = 0。
第一步、排序
第二步、双指针法。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        //a,b,c
        int left = 0;
        int right = nums.size()-1;
        sort(nums.begin(), nums.end());

        for( int i = 0; i < nums.size(); i++){
            if(nums[i] > 0){
                return result;
            }
            left = i+1;
            right = nums.size()-1;
            //对a去重
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }

            while( right > left ){ 
                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]});
                    //对bc去重
                    while( right > left && nums[right] == nums[right-1]){
                        right--;
                    }
                    while( right > left && nums[left] == nums[left+1]){
                        left++;
                    }
                    left++;
                    right--;
                }                
            }

        }
        return result;
    }
};

四、18. 四数之和

题目链接: 四数之后
解题思路,按照三题之和的解法,a+b+c+d,先把a+b求出来,再通过双指针法把c和d找到,这道题边界条件处理比较麻烦。

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> res;
        //和三数之和一样依然使用双指针法
        sort(nums.begin(), nums.end());
        int left = 0;
        int right = 0;
        for( int i = 0; i < nums.size(); i++){
      	//1、第一个点nums[i] > target不能作为单一的条件,还要确定nums[i]是不是大于0.因为
      	//负数+负数会更小
            if(nums[i] > target && nums[i] >= 0){
                break;
            }
            //对nums[n]去重
            if( i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            for(int k = i+1; k < nums.size(); k++){
                //二级剪枝
                //这个条件也要保证num[i]+nums[k]是大于0的
                if(nums[i] + nums[k] > target && nums[i] + nums[k] >= 0){
                    break;
                }
                //去重
                if( k > i+1 && nums[k] == nums[k-1]){
                    continue;
                }
				//下面的双指针操作基本和三数之和一样
                left = k+1;
                right = nums.size()-1;
                while(right > left){
                if((long)nums[i] + nums[k] + nums[left] + nums[right] < target){
                    left++;
                }else if((long)nums[i] + nums[k] + nums[left] + nums[right] > target){
                    right--;
                }else{
                    res.push_back(vector<int>{nums[i], nums[k], nums[left], nums[right]});
                    while(right > left && nums[right] == nums[right - 1]){
                        right--;
                    }
                    while(right > left && nums[left] == nums[left+1]){
                        left++;
                    }
                    left++;
                    right--;
                }
            }
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值