代码随想录day7| 四数相加、赎金信、三数之和、四数之和

四数相加

这道题可以直接使用4个for循环去求解,但是这样时间复杂度会高很多,我们可以将四个数组两两拆分,使用unordered_map容器去求解问题,首先我们遍历nums1和nums2两个数组,将其中的元素之和设置成key,将元素之和出现的次数设置成value。对于这个数组来说

nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]

map容器中就有key=-1,value =1;key=0,value=2;key=1,value=1;接下来,遍历nums3和nums4中的数,这时候我们需要判断的是-(c+d)是否在map中出现过,要是出现过,那么计数器就可以直接加上已经出现过的次数。要是还是另外出现过,就继续加。代码如下:

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

赎金信

 这道题还是很简单的,可以直接使用两个for循环暴力求解。直接给出代码:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        for(int i = 0;i < magazine.length();i++){
            for(int j = 0;j < ransomNote.length();j++){
                if(magazine[i] == ransomNote[j]){
                    ransomNote.erase(ransomNote.begin() + j);
                    break;
                }
            }
        }
        if(ransomNote.length() == 0){
            return true;
        }
        return false;
    }
};

这道题可以换一种思路,题目要求是判断ransomNote中字符能不能被magazine中的字符构成。我们可以将magazine中字符放入一个数组中,然后我们判断ransomNote中字符在这个数组中有没有出现,这样就转换成了一个哈希表的问题。

这道题和前面的异位词相同,都是使用数组作为哈希表来解题。

这里record[magazine[i]-'a']++来举个例子,magazine数组为aab的话,那么在数组中0号位置记录2,1号位置记录1,其余位置记录0。

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};
        if(ransomNote.length() > magazine.length()){
            return false;
        }
        for(int i = 0;i < magazine.length();i++)//将magazine中的元素放入到数组中
        {
            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;
    }
};

三数之和

 这道题和前面的四数相加是有区别的,前面的四数相加不需要去重的操作,所有用哈希表的做法来做的很简单,考虑到这题也可以用哈希表的思想,但是后序需要进行去重的操作,因此不适合用哈希表。

首先,我们先对数组进行排序,我们从前往后遍历整个数组,第一个数为i、第二个数为left、第三个数为right。我们需要得到的结果是nums[i]+nums[left]+nums[right]=0,我们需要对三个数都进行去重操作。

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;//如果第一个数就大于0,后面所有的数都大于0
            if(i > 0 && nums[i] == nums[i-1]) 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(right > left &&nums[left] == nums[left+1]) left++;//对第二个数进行去重
                    while(right > left && nums[right] == nums[right-1]) right--;//对第三个数进行去重
                    right--;
                    left++;
                }
            }
        }
        return result;
    }
};

四数之和

这道题的思想和三数之和一样,使用双指针法,只不过是在i的前面加了一个k,然后使用两个for循环遍历,重点在于,需要对k和i进行剪枝操作,去重操作相类似。

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());
        for(int k = 0;k < nums.size();k++)
        {
            //对k进行减枝操作
            if(nums[k] > target && nums[k] >= 0) break;
            //对k进行去重
            if(k > 0 && nums[k] == nums[k-1]) continue;
            for(int i = k+1;i < nums.size();i++)
            {
                //对i进行剪枝
                if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) break;
                //对i进行去重
                if(i > k+1 && nums[i] == nums[i-1]) continue;
                int left = i + 1;
                int right = nums.size() - 1;
                while(right > left)
                {
                    if((long)nums[k]+nums[i]+nums[left]+nums[right] > target) right--;
                    else if((long)nums[k]+nums[i]+nums[left]+nums[right] < target) left++;
                    else{
                        result.push_back(vector<int>{nums[k],nums[i],nums[left],nums[right]});
                        while(right > left && nums[left] == nums[left+1]) left++;//对left去重
                        while(right > left && nums[right] == nums[right-1]) right--;//去right去重
                        right--;
                        left++;
                    }
                }
            }
        }
        return result;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值