Code Ganker: 3Sum -- LeetCode

2014年2月9日星期日

3Sum -- LeetCode

原题链接: https://oj.leetcode.com/problems/3sum/
这道题是Two Sum的扩展,brute force时间复杂度为O(n^3), 对每三个数进行比较。这道题和Two Sum有所不同,使用哈希表的解法并不是很方便,因为结果数组中元素可能重复,如果不排序对于重复的处理将会比较麻烦,因此这道题一般使用排序之后夹逼的方法,总的时间复杂度为O(n^2+nlogn)=(n^2),空间复杂度是O(n),代码如下:
public ArrayList<ArrayList<Integer>> threeSum(int[] num)
{
    ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
    if(num==null || num.length<=2)
        return res;
    Arrays.sort(num);
    for(int i=num.length-1;i>=2;i--)
    {
        if(i<num.length-1 && num[i]==num[i+1])
            continue;
         ArrayList<ArrayList<Integer>> curRes = twoSum(num,i-1,-num[i]);
         for(int j=0;j<curRes.size();j++)
         {
             curRes.get(j).add(num[i]);
         }
         res.addAll(curRes);
    }
    return res;
}
private ArrayList<ArrayList<Integer>> twoSum(int[] num, int end,int target)
{
    ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
    if(num==null || num.length<=1)
        return res;
    int l = 0;
    int r = end;
    while(l<r)
    {
        if(num[l]+num[r]==target)
        {
            ArrayList<Integer> item = new ArrayList<Integer>();
            item.add(num[l]);
            item.add(num[r]);
            res.add(item);
            l++;
            r--;
            while(l<r&&num[l]==num[l-1])
                l++;
            while(l<r&&num[r]==num[r+1])
                r--;
        }
        else if(num[l]+num[r]>target)
        {
            r--;
        }
        else
        {
            l++;
        }
    }
    return res;
}
注意,在这里为了避免重复结果,对于已经判断过的数会skip掉,这也是排序带来的方便。 这道题考察的点其实和Two Sum差不多,Two Sum是3Sum的一个subroutine, 不过更加综合一些,实现上更加全面,需要注意细节,面试中比较常见的一道题。此题更加复杂的扩展是4Sum,请参见4Sum -- LeetCode.

2 条评论:

  1. 感觉这方法太牛了。。一点不懂就是n^2的复杂度是因为主函数的两个for循环?那为啥twoSum的时间复杂度没加进去?

    回复删除
    回复
    1. twoSum的时间复杂度是O(n),主函数的内循环和twoSum这个函数是并列的,所以总复杂度是O(n*(n+n))=O(2*n^2)=O(n^2).

      删除