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

17 篇文章 0 订阅

454、四数相加Ⅱ383、赎金信15、三数之和四数之和

四数相加

对于四数相加,我们可以定义一个map用来记录nums1与nums2的和对应次数,再遍历nums3与nums4,如果存在c与d使得a、b、c、d之和为零,我们就记录下这个次数,最后使这个次数相加即可。

代码如下:

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

383、赎金信

首先,我们可以定义一个map,用于记录magzine中的元素次数,遍历一次magzine,让map中对应的次数+1;然后遍历一次ransomNote,让map中对应的次数-1,如果这个次数在访问完某个元素后小于零了,我们就返回false;如果顺利遍历完ransomNote数组,那我们就返回true;

代码

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map<int,int> map1;
        for(auto mag:magazine)
            map1[mag-'a']++;
        for(auto ran:ransomNote)
        {
            map1[ran-'a']--;
            if(map1[ran-'a']<0)
            return false;
        }
        return true;
    }
};

15、三数之和

对于三数之和,由于题干没有要求是否有序,也没有要求要返回下标,因此我们可以先给他们进行排序。
我们可以定义三个指针,包括遍历指针,左指针和右指针,其中,遍历指针用来遍历该数组,左指针指的是遍历指针右侧的左端指针,右指针指的是遍历指针右侧的右端指针。如图
在这里插入图片描述
因为我们已经对数组进行了排序,因此 数组是从小到大的顺序。
对于每一个遍历的ii,如果满足

nums[ii]>0  说明右侧的元素都大于零,因此无需再遍历

如果满足

num[ii]+num[left]+num[righgt]==0  我们就将这三个数保存起来

那么我们将这三个元素保存起来,如果

num[ii]+num[left]+num[righgt]<0 说明三个数太小了,我们让left右移,使三个数大一点

如果

num[ii]+num[left]+num[righgt]>0 说明三个数太大了,我们让right左移,使三个数小一点

然而如果仅仅这样做,一定会有重复的元素,那么该如何去重呢?
当我们移动指针时,我们可以判断移动指针前后,指针是否重复,如果重复,让它们再移动一位。
对于ii而言
为了避免指针越界,我们可以让ii>0时进行判断,如果nums[ii]==nums[ii-1]时,让ii右移,即ii已经判别过了,无需判别相同的元素
对于left与right,处理方法相同,当我们访问到满足条件的left与right时,我们判断left与left+1所指是否相同,如果相同让left指向下一个指针,right同理,这样之后,让left与right分别向内移动即可。

代码

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

四数之和

与上面三数之和的题目类似,只不过需要双重for循环遍历该数组,并且不能设置ii>target的情况,最坑的是,这道题判定案例有一个是溢出了,因此我们对四个数进行相加时要进行转换为long类型。

代码

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> answer;
        sort(nums.begin(),nums.end());
        for(int ii = 0;ii<nums.size();ii++)
        {
        while(ii>0&&ii<nums.size()&&nums[ii]==nums[ii-1]) ++ii;
            for(int jj = ii+1;jj<nums.size();jj++)
            {   while(jj>(ii+1)&&jj<nums.size()&&nums[jj]==nums[jj-1]) ++jj;
                int left = jj+1;
                int right = nums.size()-1;
                while(left<right)
                {
                if((long)nums[ii]+nums[jj]+nums[left]+nums[right]>target) --right;
                else if((long)nums[ii]+nums[jj]+nums[left]+nums[right]<target) ++left;
                else 
                    {
                        answer.push_back(vector<int>{nums[ii],nums[jj],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 answer;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值