1. 程式人生 > >leetcode解題筆記:Two sum系列解題思路

leetcode解題筆記:Two sum系列解題思路

  • Two Sum
  • 3Sum
  • 3Sum Closest

Two Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9
, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].

解法一

一下能想到的思路就是內外兩個迴圈找和為target的兩個數字,這樣的複雜度是O(n*n)。

解法二

想到能否用雜湊表,每遍歷到一個元素num,看target-num是否在hash表中,如果在就得出答案,如果不在就將當前num放入雜湊表中。

public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map= new HashMap<Integer,Integer>();
        int
[] result = new int[2]; for(int i=0;i<nums.length;i++){ if(map.containsKey(target-nums[i])){ result[0]=i; result[1] = map.get(target-nums[i]); break; }else{ map.put(nums[i],i); } } return
result; }

這種解法是O(n)的時間複雜度,但要額外增加O(n)的雜湊表儲存空間。

解法三

可以換個角度來考慮問題,如果給定的陣列是已排序的陣列,那麼就可以設定lo和hi兩個指標,如果這兩個數字的和比target要大,那麼就lo++,否則hi–。這樣排序陣列需要O(NlogN),找和的過程需要O(N),但是空間是in-place的。

其實這是167. Two Sum II - Input array is sorted丟擲的問題。這樣我們就不用對陣列排序了。

public int[] twoSum(int[] numbers, int target) {
        int i = 0;
        int j = numbers.length-1;
        int[] result = new int[2];
        while(j>i){
            if(numbers[i]+numbers[j] == target){
                result[0] = i+1;
                result[1] = j+1;
                break;
            }else if(numbers[i]+numbers[j] < target){
                i++;
            }else{
                j--;
            }
        }
        return result;
    }

時間複雜度為O(N)

3Sum

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

Note: 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]
]

這次是尋找3個數的和為0的組合。可以接著2Sum解法三的思路來想。首先先對陣列排序;然後從頭開始每次取一個數作為sum,則此題變成了在後面的陣列中尋找兩個數其和為-sum,就和上面的過程一樣。

這裡還要注意一個重複的問題,當我們對陣列排序後,重複的數是排列在一起的,此時若已經取過一個解後就不要再取重複的解了。

public List<List<Integer>> threeSum(int[] nums) {
        int len = nums.length;
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        for(int i=0;i<len;i++){
            //防止重複解
            if(i==0 || nums[i]!=nums[i-1]){
                int sum = 0-nums[i];
                int lo = i+1;
                int hi = len-1;
                while(lo<hi){
                    if(nums[lo]+nums[hi] == sum){
                        result.add(Arrays.asList(nums[i], nums[lo], nums[hi]));
                        //防止重複解
                        while(lo<hi && nums[lo] == nums[lo+1])lo++;
                        while(lo<hi && nums[hi] == nums[hi-1])hi--;

                        lo++;
                        hi--;
                    }else if(nums[lo]+nums[hi]>sum){
                        hi--;
                    }else{
                        lo++;
                    }
                }
            }

        }
        return result;

    }

這種解法的時間複雜度為O(N*N)

3Sum Closest

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

其實和上面的過程一樣,只不過是相等比較轉換成了差值的比較。

public int threeSumClosest(int[] nums, int target) {
        int len = nums.length;
        if(len<3) return -1;
        Arrays.sort(nums);
        int result = nums[0]+nums[1]+nums[2];
        for(int i=0;i<len-2;i++){
                int lo = i+1;
                int hi = len-1;
                while(lo<hi){
                    int sum = nums[i]+nums[lo]+nums[hi];
                    if(sum == target){
                        return sum;
                    }else{
                        if(Math.abs(sum-target) < Math.abs(target-result)){
                            result = sum;
                        }
                        if(sum>target){
                            hi--;
                        }else{
                            lo++;
                        }
                    }
                }

        }
        return result;
    }

這種解法的時間複雜度為O(N*N)

總結

可以發現,two sum的解法三是適用於其他變種的,都是在陣列已排序的情況下根據當前和與target的比較情況移動指標,其中也要特別注意避免重複解的問題。