查找数组中和为某给定值的三元组

问题描述

给定一个数组arr,以及一个数字target。求数组中和为target的三个数。要求给出所有解。数组中的每个数在每组解中只能出现一次。

解法

方法一:如果用暴力方法,时间复杂度是 o(n3)

方法二:利用C++11中的unordered_multimap,本题复杂度可降至 O(n2)

#include<iostream>
#include<vector>
#include<unordered_map>
#include <set>
#include <algorithm>
using namespace std;
class Solution {
public:
    vector<vector<int> > threeSum(vector<int> &num, int sum) {
        unordered_multimap<int, int> hashmap;
        vector<vector<int> > result;
        for(int i=num.size()-1; i>=0; i--)
        {
            hashmap.insert( {num.at(i), num.size()-i-1} );
        }
        /*
        for(auto iter1=hashmap.begin(); iter1!=hashmap.end(); iter1++)
        {
            cout<<(*iter1).first<<" ";
            cout<<(*iter1).second<<endl;
        }
        cout<<endl;
        */
        for(auto iter1=hashmap.begin(); iter1!=hashmap.end(); iter1++)
        {
            int target = sum -(*iter1).first;
            auto iter = iter1;
            iter++;
            if (iter == hashmap.end() )
                continue;
            for(auto iter2=iter; iter2!=hashmap.end(); iter2++)
            {
                auto iterres = hashmap.equal_range( target - (*iter2).first );
                if (iterres.first == iterres.second)//下界pair和上界pair相等,没找到
                {
                    continue;
                }
                for(auto get=iterres.first; get!=iterres.second; get++)
                {
                    //get遍历所有pair(一对mapiterator),(*get)取出一个pair,(*get).second表示第二个map变量
                    //if (get == hashmap.end() || (*iter1).second >= (*iter2).second || (*iter2).second >= (*get).second )
                    if (get == hashmap.end() || (*iter1).second == (*iter2).second || (*iter2).second == (*get).second || (*iter1).second == (*get).second ) //后面三个都不能遗漏!
                    {
                        continue;
                    }
                    int res = (*get).first;
                    int arr[] = { (*iter2).first, (*iter1).first, res};
                    sort(arr, arr+3);
                    vector<int> trip(arr, arr+3);
                    result.push_back(trip);
                }
            }
        }
        set< vector<int> > tmpres;
        for(int i=0; i<result.size(); i++)
        {
            tmpres.insert( result.at(i) );
        }
        result.clear();
        for(auto iter=tmpres.begin(); iter!=tmpres.end(); iter++)
        {
            result.push_back( *iter );
        }
        return result;
    }
};
int main()
{
    Solution sol;
    //int arr[] = {-1, 0, 1, 2, -1, -4};
    int arr[] = {7,5,-8,-6,-13,7,10,1,1,-4,-14,0,-1,-10,1,-13,-4,6,-11,8,-6,0,0,-5,0,11,-9,8,2,-6,4,-14,6,4,-5,0,-12,12,-13,5,-6,10,-10,0,7,-2,-5,-12,12,-9,12,-9,6,-11,1,14,8,-1,7,-13,8,-11,-11,0,0,-1,-15,3,-11,9,-7,-10,4,-2,5,-4,12,7,-8,9,14,-11,7,5,-15,-15,-4,0,0,-11,3,-15,-15,7,0,0,13,-7,-12,9,9,-3,14,-1,2,5,2,-9,-3,1,7,-12,-3,-1,1,-2,0,12,5,7,8,-7,7,8,7,-15};
    vector<int> num(arr, arr+200);
    vector<vector<int> > res = sol.threeSum(num, 10);
    for(int i=0; i<res.size(); i++)
    {
        for(int j=0; j<res.at(i).size(); j++)
        {
            cout<<res.at(i).at(j)<<" ";
        }
        cout<<endl;
    }
    return 0;
}

以上解法(稍加修改),提交给leetcode(第15题)后仍然报错(Time Limit Exceeded)。难道有更低复杂度的解法吗?
希望有高手能指点一二。

方法三:先排序,然后二分查找,复杂度可降至 O(nlogn)

 vector<vector<int> > threeSum(vector<int> &num) 
 {
        vector<vector<int> > res;
        if(num.empty())
            return res;
        sort(num.begin(), num.end()); //nlogn

        for(int i=0; i+2<num.size(); i++) //n
        {
            if(i>0 && num[i] == num[i-1])
                continue;
            int left(i+1), right(num.size()-1);
            while(left < right)//logn
            {
                if(left>i+1 && num[left] == num[left-1])
                {
                    left++;
                    continue;
                }
                if(right < num.size()-1 && num[right] == num[right+1])
                {
                    right--;
                    continue;
                }
                int sum = num[i] + num[left] + num[right];
                if(sum < 0) left++;
                else if(sum > 0) right--;
                else
                {
                    res.push_back( vector<int> {num[i], num[left], num[right]} );
                    right--;
                    left++;
                }
            }
        }
        return res;
    }

同理,如果需要查找数组中和为某给定值的四元组,用法三解决,时间复杂度为 O(n2logn)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值