2023-07-15力扣每日一题

链接:

18. 四数之和

题意:

一个数组n,一个目标值t,在数组内找四个数字和等于t,求能有多少种组合

解:

0716:一看怎么昨天卡没打,原来昨天做的第一题不是每日一题,麻了

n很小,200,那么先排序,然后弄一个双指针开双循环l,r,确定每个组合的最大数字-数字4和最小数字-数字1,然后计算t-num1-num4,就可以得到该组合对应num2+num3 我们设为tL,然后再弄一个双指针ll,rrl,r内找,这时,由于数组已经排序了,所以如果nums[ll]+nums[rr]<tL右移LL,如果nums[ll]+nums[rr]>tL左移RR

nums[ll]+nums[rr]==tL时,我们只需要将其和记录结果的容器里最后一个比较是否相同就可以达到去重的效果(我直接用了暴力比较QWQ)

去重:

1、由于已经排序,所以当新的L和上一个L相同时,跳过。相同数字第一个遇到的一定提供最大的范围(即最小的L),比如 3,3,0,0,0,0…,取第一个3作为L,num2-4还可以选择第二个3,和后面的所有数字;选取第二个3做为L,num2-4只能选择后面的数字,所以选取第二个3做为L所推导的结果包含在取第一个3作为L的结果

2、现在已经确定了该组合的第一个数字num1=nums[L],这边要开第二重循环去选取第四个数字num4=nums[R],同样,当新的R跟上一个R相同时,跳过,原因同 1

3、确定了num1和num4,再找num2和num3就很简单了,上面也提过了,不用双循环,顶多遍历一遍 l,r

4、由于num1逐渐增大且不重复,在同一个num1下num4逐渐减小且不重复,所以答案容器里末尾要么是不同的num1开头,要么是相同的num1开头不同的num4结尾,要么是相同的num1num4,前面两种情况和现在明显不相同,在第三种情况下,由于LL和RR的起始值固定,且移动方向固定(向数组中间),且数组有序,所以如果不和容器末尾相同,则在容器中一定不存在与之相同的答案

5、由此可知,容器中答案排序是:num1从小到大,num1相同时num4从大到小,num1和num4均相同时num2num3从两边到中间

实际代码:

#include<bits/stdc++.h>
using namespace std;
bool comp(const vector<int>& A,const vector<int>& B)
{
    for(int i=0;i<4;i++)
    {
        if(A[i]!=B[i])return true;
    }
    return false;
}
vector<vector<int>> fourSum(vector<int>& nums, int target)
{
    sort(nums.begin(),nums.end());//先排序 
    //for(auto i:nums) cout<<i<<" ";
    //cout<<endl;
    vector<vector<int>>ans;int lg=nums.size();
    for(int l=0,r=lg-1;l<r;l++)
    {
        if(l && nums[l-1]==nums[l] )continue;//确定数字1 不重复 
        for(;l<r;r--)
        {
            if(r<lg-1 && nums[r+1]==nums[r]) continue;//确定数字4 在当前数字1不重复 
            //cout<<l<<"-N1-"<<r<<endl;
            long long targetL=(long long)target-nums[l]-nums[r];//新的目标 
            for(int ll=l+1,rr=r-1;ll<rr;)
            {
                //cout<<ll<<"-N2-"<<rr<<endl;
                long long now=(long long)nums[ll]+nums[rr];//当前值 
                if(now==targetL)
                {
                    vector<int>temp{nums[l],nums[ll],nums[rr],nums[r]};
                    //去重 
                    if(!ans.empty() && comp( temp,*(ans.rbegin()) )) ans.push_back(temp);
                    if(ans.empty()) ans.push_back(temp);
                    ll++;rr--;
                }
                else if(now<targetL) ll++;
                else rr--;
            }
        }
        r=lg-1;//重置右指针 
    }
    return ans;
}
int main()
{
    vector<int> nums;int target;
    cin>>target;int temp;
    while(cin>>temp)
    {
        nums.push_back(temp);
    }
    vector<vector<int>>ans=fourSum(nums,target);
    for(auto &i:ans)
    {
        for(auto j:i)
        {
            cout<<j<<" ";
        }
        cout<<endl;
    }
    return 0;
}

限制:

  • 1 <= nums.length <= 200
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值