DAY7 - 454.四数相加II, 383.赎金信, 15.三数之和, 18.四数之和

454.四数相加II

和昨天那个两数之和为target有点像。

一开始想的是创建四个map分别存数组,但是这样跟暴力算法也没区别。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int,int> map;
        int res=0;
        for(int n1:nums1){
            for(int n2:nums2){
                int sum=n1+n2;
                auto a=map.find(sum);
                if(a==map.end()){
                    map.insert({sum,1});
                }else{
                    a->second++;
                }
            }
        }
        for(int n3:nums3){
            for(int n4:nums4){
                auto a=map.find(-n3-n4);
                if(a!=map.end()){
                    res+=a->second;
                }
            }
        }
        return res;
        
    }
};

小tips:

  • 设置auto a=map.find(sum);在后面要a->second++; 的时候可以避免重复计算,降低时间复杂度。
  • 计算结果数量的时候 res+=a->second;,不能只加一次。

383.赎金信

一开始想到的省事的办法是用unorderd_map,但是题解里面说用um要维护哈希表还有使用哈希函数,费时间,在数据量大的时候更耗时,所以还是使用数组。

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int m[26]={0};
        for(char c:magazine){
            m[c-'a']++;
        }
        for(char c:ransomNote){
            if(--m[c-'a']<0) return false;
        }
        return true;
    }
};

可以在代码最前面加上一个判断,减少无用操作,提升运行速度

if (ransomNote.size() > magazine.size()) {
            return false;
        }

15.三数之和

尝试使用哈希。

要去重的话一个通用思路是要排序,这样才能把一样的元素放在一起。

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

        for(int i=0;i<nums.size();i++){
            if(nums[i]>0) break;
            if(i>0&&nums[i]==nums[i-1]) continue; //去重

            unordered_set<int> set;
            for(int j=i+1;j<nums.size();j++){
                //去重b=c时的情况
                if (j>i+2 && nums[j]==nums[j-1] && nums[j-1]==nums[j-2]) continue;
                int target=0-nums[i]-nums[j];
                if(set.find(target)!=set.end()){
                    res.push_back({nums[i],nums[j],target});
                    set.erase(target);//去重
                }else{
                    set.insert(nums[j]);
                }
            }
        }

        return res;
    }
};

这个去重b==c时候的条件比较难想,还有这个set.erase(target)

通过了但是程序执行时间很长。

双指针写法执行时间快了不少,而且内存消耗也更低。

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

        for(int i=0;i<nums.size();i++){
            if(nums[i]>0) break;
            if(i>0&&nums[i]==nums[i-1]) continue;

            int left=i+1;
            int right=nums.size()-1;

            while(left<right){
                int sum=nums[i]+nums[left]+nums[right];
                if(sum==0){
                    res.push_back({nums[i],nums[left],nums[right]});
                    while(left<right&&nums[right]==nums[right-1]) right--;
                    while(left<right&&nums[left]==nums[left+1]) left++;
                    left++;
                    right--;
                }else if(sum>0) right--;
                else left++;
            }
        }
        return res;
    }
};

18.四数之和

在一个数组内并且要求去重,和三数之和比较像,考虑用双指针,for循环写两层。

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> res;
        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[i]+nums[j]>target&&nums[i]+nums[j]>=0) break;
                if(j>i+1&&nums[j]==nums[j-1]) continue;
                
                int left=j+1;
                int right=nums.size()-1;
                while(left<right){
                    long sum=(long)nums[i]+nums[j]+nums[left]+nums[right];
                    if(sum==target){
                        res.push_back({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--;
                    }else if(sum<target) left++;
                    else right--;
                }
                
            }
        }
        return res;
    }
};
  • 注意内层循环 if(j>i+1&&nums[j]==nums[j-1]) continue; 要和三数之和用哈希法 if (j>i+2 && nums[j]==nums[j-1] && nums[j-1]==nums[j-2]) continue; 区分。j只要管好自己不要重复就行了。
  • long sum=(long)nums[i]+nums[j]+nums[left]+nums[right]; 提交时提示sum会溢出,所以用long
posted @ 2025-03-20 00:09  ChloeChen0221  阅读(266)  评论(0)    收藏  举报