1. 程式人生 > >【LeetCode】3Sum 解題報告

【LeetCode】3Sum 解題報告

這道題憑我現有知識實在解答不上來,只好網上搜索解法,才發現 K Sum 是一類問題,但是網上沒有比較簡潔的程式碼,我想對於初學者來說,可能還是想先看看這道題怎麼解,然後才有興趣去看其擴充套件吧。

【題目】

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a
     ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.
    For example, given array S = {-1 0 1 2 -1 -4},

    A solution set is:
    (-1, 0, 1)
    (-1, -1, 2)
【解析】

K Sum問題是一個系列,部落格 http://tech-wonderland.net/blog/summary-of-ksum-problems.html 總結得比較完整,有興趣可以去看。

作為初學者,我們用最簡潔的思路來說一下這道題怎麼解。

暴力解決法是每個人都能想到的,三層for迴圈,時間複雜度是O(n^3),而且還要處理重複的問題,顯然不是題目想要的解法。

那能不能降到O(n^2)?排序演算法的時間複雜度為O(nlgn),小於O(n^2),那麼我們不妨先對陣列排個序。

排序之後,我們就可以對陣列用兩個指標分別從前後兩端向中間掃描了,如果是 2Sum,我們找到兩個指標之和為target就OK了,那 3Sum 類似,我們可以先固定一個數,然後找另外兩個數之和為第一個數的相反數就可以了。

程式碼不難,先看了再說。

【Java程式碼】O(n^2)

public class Solution {
    List<List<Integer>> ret = new ArrayList<List<Integer>>();
    
    public List<List<Integer>> threeSum(int[] num) {
        if (num == null || num.length < 3) return ret;
        
        Arrays.sort(num);
        
        int len = num.length;
        for (int i = 0; i < len-2; i++) {
            if (i > 0 && num[i] == num[i-1]) continue;
            find(num, i+1, len-1, num[i]); //尋找兩個數與num[i]的和為0
        }
        
        return ret;
    }
    
    public void find(int[] num, int begin, int end, int target) {
        int l = begin, r = end;
        while (l < r) {
            if (num[l] + num[r] + target == 0) {
                List<Integer> ans = new ArrayList<Integer>();
                ans.add(target);
                ans.add(num[l]);
                ans.add(num[r]);
                ret.add(ans); //放入結果集中
                while (l < r && num[l] == num[l+1]) l++;
                while (l < r && num[r] == num[r-1]) r--;
                l++;
                r--;
            } else if (num[l] + num[r] + target < 0) {
                l++;
            } else {
                r--;
            }
        }
    }
}

注意,對於 num[i],尋找另外兩個數時,只要從 i+1 開始找就可以了。

這種寫法,可以避免結果集中有重複,因為陣列時排好序的,所以當一個數被放到結果集中的時候,其後面和它相等的直接被跳過。