1. 程式人生 > 其它 >LeetCode No15. 三數之和

LeetCode No15. 三數之和

題目

給你一個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有和為 0 且不重複的三元組。

注意:答案中不可以包含重複的三元組。

示例 1:

輸入:nums = [-1,0,1,2,-1,-4]
輸出:[[-1,-1,2],[-1,0,1]]

示例 2:

輸入:nums = []
輸出:[]

示例 3:

輸入:nums = [0]
輸出:[]

思路

首先第一反應就是暴力,三重迴圈,然後時間複雜度O(n^3),按照題目給的資料範圍應該不會超時,然而寫完之後提交直接超時。那就優化唄,看題目的樣例,似乎是對返回的順序什麼的沒有要求,那麼就想到排序,然後對排序後的陣列去取值,這樣就想到如下兩種方法:

二分查詢

既然三重迴圈不行,那我減少一層迴圈試試,先用兩層迴圈找到兩個數a、b,因為需要三個數之和為0,那麼另外一個數必然是 -(a+b),因為陣列已經有序,找這個數就可以用二分,時間複雜度為O(n^2*log(n))。

雙指標

既然已經能減少一層迴圈,那麼是否還能再減少一層迴圈呢?顯然是可以的,用一層迴圈遍歷出第一個數a,對於剩下的兩個數,由於陣列已經排好序了,只需要用兩個指標去從陣列的頭和尾取數,只要找到的兩個數和a相加等0即可。

AC程式碼

二分查詢

點選檢視程式碼
class Solution {

    private int b_search(int[] nums, int low, int high, int num) {
        while( low <= high ) {
            int mid = ( low + high ) / 2;
            if( nums[mid] == num ) {
                return mid;
            } else if( nums[mid] > num ){
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return -1;
    }

    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        int len = nums.length;
        if( len < 3 ){
            return res;
        }
        Arrays.sort(nums);
        for(int i=0; i<len; i++) {
            if( i!=0 && nums[i-1]==nums[i] ) {
                continue;
            }
            int last = i+1;
            while( last < len-1 ) {
                if( last > i+1 && nums[last-1]==nums[last] ) {
                    last ++;
                    continue;
                }
                int num = nums[i] + nums[last];
                if( num > 0 ) {
                    break;
                }
                int ind = b_search(nums, last+1, len-1, num*-1);
                if( ind!=-1 ) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[last]);
                    list.add(nums[ind]);
                    res.add(list);
                }
                last ++;
            }
        }
        return res;
    }
}

雙指標

點選檢視程式碼
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        int lasta = -100005;
        int n = nums.length;
        Arrays.sort(nums);
        for(int i=0; i<n; i++) {
            int a = nums[i];
            if( lasta==a ) {
                continue;
            }
            lasta = a;
            int low = i+1;
            int high = n - 1;
            while( low < high ) {
                int sum = a + nums[low] + nums[high];
                if( sum>0 ) {
                    high --;
                } else if( sum < 0 ) {
                    low ++;
                } else {
                    List<Integer> list = new ArrayList<>();
                    list.add(a);
                    list.add(nums[low]);
                    list.add(nums[high]);
                    res.add(list);
                    while(low<high && nums[low]==nums[low+1]) {
                        low ++;
                    }
                    while(low<high && nums[high]==nums[high-1]) {
                        high --;
                    }
                    low ++;
                    high --;
                }
            }
        }
        return res;
    }
}