程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 4Sum -- LeetCode

4Sum -- LeetCode

編輯:C++入門知識

原題鏈接: http://oj.leetcode.com/problems/4sum/
這道題要求跟3Sum差不多,只是需求擴展到四個的數字的和了。我們還是可以按照3Sum中的解法,只是在外面套一層循環,相當於求n次3Sum。我們知道3Sum的時間復雜度是O(n^2),所以如果這樣解的總時間復雜度是O(n^3)。代碼如下:

public ArrayList> fourSum(int[] num, int target) {
    ArrayList> res = new ArrayList>();
    if(num==null||num.length==0)
        return res;
    Arrays.sort(num);
    for(int i=num.length-1;i>2;i--)
    {
        if(i==num.length-1 || num[i]!=num[i+1])
        {
            ArrayList> curRes = threeSum(num,i-1,target-num[i]);
            for(int j=0;j threeSum(int[] num, int end, int target)
{
    ArrayList> res = new ArrayList>();
    for(int i=end;i>1;i--)
    {
        if(i==end || num[i]!=num[i+1])
        {
            ArrayList> curRes = twoSum(num,i-1,target-num[i]);
            for(int j=0;j twoSum(int[] num, int end, int target)
{
    ArrayList> res = new ArrayList>();
    int l=0;
    int r=end;
    while(l item = new ArrayList();
            item.add(num[l]);
            item.add(num[r]);
            res.add(item);
            l++;
            r--;
            while(ltarget)
        {
            r--;
        }
        else
        {
            l++;
        }
    }
    return res;
}
上述這種方法比較直接,根據3Sum的結果很容易進行推廣。那麼時間復雜度能不能更好呢?其實我們可以考慮用二分法的思路,如果把所有的兩兩pair都求出來,然後再進行一次Two Sum的匹配,我們知道Two Sum是一個排序加上一個線性的操作,並且把所有pair的數量是O((n-1)+(n-2)+...+1)=O(n(n-1)/2)=O(n^2)。所以對O(n^2)的排序如果不用特殊線性排序算法是O(n^2*log(n^2))=O(n^2*2logn)=O(n^2*logn),算法復雜度比上一個方法的O(n^3)是有提高的。
思路雖然明確,不過細節上會多很多情況要處理。首先,我們要對每一個pair建一個數據結構來存儲元素的值和對應的index,這樣做是為了後面當找到合適的兩對pair相加能得到target值時看看他們是否有重疊的index,如果有說明它們不是合法的一個結果,因為不是四個不同的元素。接下來我們還得對這些pair進行排序,所以要給pair定義comparable的函數。最後,當進行Two Sum的匹配時因為pair不再是一個值,所以不能像Two Sum中那樣直接跳過相同的,每一組都得進行查看,這樣就會出現重復的情況,所以我們還得給每一個四個元素組成的tuple定義hashcode和相等函數,以便可以把當前求得的結果放在一個HashSet裡面,這樣得到新結果如果是重復的就不加入結果集了。
代碼如下:
private ArrayList> twoSum(ArrayList pairs, int target){
    HashSet hashSet = new HashSet();
    int l = 0;
    int r = pairs.size()-1;
    ArrayList> res = new ArrayList>();
    while(l=rEnd;j--)
                {
                    if(check(pairs.get(i),pairs.get(j)))
                    {
                        ArrayList item = new ArrayList();
                        item.add(pairs.get(i).nodes[0].value);
                        item.add(pairs.get(i).nodes[1].value);
                        item.add(pairs.get(j).nodes[0].value);
                        item.add(pairs.get(j).nodes[1].value);
                        //Collections.sort(item);
                        Tuple tuple = new Tuple(item);
                        if(!hashSet.contains(tuple))
                        {
                            hashSet.add(tuple);
                            res.add(tuple.num);
                        }
                    }                        
                }
            }
            l = lEnd+1;
            r = rEnd-1;
        }
        else if(pairs.get(l).getSum()+pairs.get(r).getSum()>target)
        {
            r--;
        }
        else{
            l++;
        }
    }
    return res;
}
private boolean check(Pair p1, Pair p2)
{
    if(p1.nodes[0].index == p2.nodes[0].index || p1.nodes[0].index == p2.nodes[1].index)
        return false;
    if(p1.nodes[1].index == p2.nodes[0].index || p1.nodes[1].index == p2.nodes[1].index)
        return false;
    return true;
}
第二種方法比第一種方法時間上還是有提高的,其實這道題可以推廣到k-Sum的問題,基本思想就是和第二種方法一樣進行二分,然後兩兩結合,不過細節就非常復雜了(這點從上面的第二種解法就能看出來),所以不是很適合在面試中出現,有興趣的朋友可以進一步思考或者搜索網上材料哈。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved