1. 程式人生 > >查詢陣列中和為某給定值的三元組

查詢陣列中和為某給定值的三元組

問題描述

給定一個數組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)