【51Nod三级题】4个数和为0

题解:

这道题有很多方法,我在LeetCode上做过这道题,由于时间长,只是隐约记到大概思路,后来还是将原来的做法翻出来看明白,重新将这道题做了,题多而不去弄懂每道题的精髓和本质,实际上和浪费时间没有区别,所以总结下一下,由于这道题有很多解法,只写一种,后续来补。

这道题首先要用到哈希表,也就是map来存,我一开始做的时候遇到了不少的坑,比如-1 2 -3 2这种,我一直想着如果遇到1 -3和2 2的组合,是否还需要特殊处理之类的问题,凡是四个数可以相加为0的,肯定会有这种-1 2和-3 2的组合,所以只需要顺序考虑即可。

首先预处理排序,然后求所有不重合的两个数相加的组合,用map保存起来,键为和,值为vector<pair<int,int>>,保存两个值的索引,比如五个数,预处理一共要执行4 + 3 + 2 + 1,由此可知,pair中的两个索引也是顺序,以便后面二分查找。

预处理完后,双重循环遍历,对于两个数而言a,b,则查找值就为0-a-b,如果查找到了,就对它的值进行二分查找,索引均要大于第二个数的索引,如果查找到了,那么这两个数必然和a,b的索引是不相同,这样就可以得到四个数为0的情况。

AC代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <unordered_map>
#include <set>
#include <queue>
#define MAX_INF 0x3f3f3f
#define ll long long
#define ull unsigned long long
const int MAXN = 2e5+10;
const int MOD = 1e9+7;
using namespace std;
#define CLR(a, b) memset((a), (b),sizeof((a)))
#define srt(v) sort(v.begin(),v.end())
#define grtsrt(v) sort(v.begin(),v.end(),greater<ll>())
#define mnv(v) *min_element(v.begin(),v.end())
#define mxv(v) *max_element(v.begin(),v.end())
#define G_priority_queue(v, w) priority_queue<v, vector<v>, greater<v> > w
#define L_priority_queue(v, w) priority_queue<v, vector<v>, less<v> > w
#define For_equal(p ,s, e) for(p = s;p <= e;p++)
#define For_nonequal(p, s, e) for(p = s;p < e;p++)
//ll dp[MAXN];
//ll a[1005][1005];
ll b[1005];
int main(){
    int n, m;
    int i, j, k;
    ll t;
    int cnt = 0;
    ll sum = 0;
    ll miv,mav;
    int flag = 0;
    map<ll, vector<pair<int, int>>> record;
    cin>>n;
    for(i = 0 ; i < n ; ++i)
        cin>>b[i];
    sort(b, b+n);
    for(i=0;i<n-1;i++){
        for(j=i+1;j<n;++j){
            record[b[i]+b[j]].push_back(make_pair(i, j));
        }
    }
    for(i=0;i<=n-4;++i){
        for(j=i+1;j<=n-3;++j){
            t = 0 - b[i] - b[j];
            if(b[j+1] + b[j+2] > t || b[n-1] + b[n-2] < t)
                continue;
            if(record.find(t) == record.end())
                continue;
 
            vector<pair<int, int>>::iterator iter = lower_bound(record[t].begin(),
                    record[t].end(), make_pair(j+1, j+1));
            if(iter != record[t].end()){
                //cout<< b[i] << " " << b[j] << " " << b[iter->first] <<" " << b[iter->second]<<"\n";
                flag = 1;
                break;
            }
        }
        if(flag)
            break;
    }
    if(flag)
        cout<<"Yes"<<"\n";
    else
        cout<<"No"<<"\n";
    return 0;
}

AC代码:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n = nums.size();
        vector<vector<int>> res;
 
        if ( n < 4 )
            return res;
 
        sort( nums.begin(), nums.end() );
        unordered_map<int, vector<pair<int, int>>> record;
        for ( int i = 0 ; i < n - 1 ; i = next_index(nums, i) )
            for ( int j = i + 1 ; j < n; j = next_index(nums, j) )
                record[nums[i] + nums[j]].push_back(make_pair(nums[i],nums[j]));
 
        for ( int i = 0 ; i <= n - 4 ;  i = next_index(nums, i) ){
            for ( int j = i + 1 ; j <= n - 3 ; j = next_index(nums, j) ){
                int t = target - nums[i] - nums[j];
 
                if ( nums[j+1] + nums[j+2] > t || nums[n-1] + nums[n-2] < t )
                    continue;
 
                if ( record.find(t) == record.end() )
                    continue;
 
                vector<pair<int, int>>::iterator iter = lower_bound(record[t].begin(), record[t].end(),
                        make_pair(nums[j+1], nums[j+1]));
                
                for ( ; iter != record[t].end() ; iter++ ) 
                    res.push_back( {nums[i], nums[j], iter->first, iter->second} );
            }
        }
        return res;
    }
 
private:
 
    int next_index( const vector<int>& nums, int index ){
        for ( int i = index + 1 ; i < nums.size() ; i ++ )
            if ( nums[index] != nums[i] )
                return i;
        return nums.size();
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~Lomiss~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值