1. 程式人生 > 實用技巧 >團滅二數之和、三數之和、四數之和

團滅二數之和、三數之和、四數之和

1.兩數之和

題目連結

Leetcode1 兩數之和

題目描述

解題思路

1.暴力法

雙重for迴圈,時間複雜度O(n*n)

2.排序+雙指標

3.雜湊表

AC程式碼

//利用雜湊表,一步到位,時間複雜度O(n)
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; ++i) {
            if (hashtable.containsKey(target - nums[i])) {
                return new int[]{hashtable.get(target - nums[i]), i};
            }
            hashtable.put(nums[i], i);
        }
        return new int[0];
    }
}

2.三數之和

題目連結

Leetcode15 三數之和

題目描述

解題思路

1.最樸素的解法:暴力,三重for迴圈,可能會超時

2.排序+雙指標

注意本題不適合採用雜湊表,如果採用雜湊表,需要去重操作,需要注意更多的細節。

首先對陣列進行排序,排序後固定一個數 nums[i],再使用左右指標指向nums[i]後面的兩端,數字分別為 nums[L]和nums[R],計算三個數的和 sum,判斷是否滿足為 0,滿足則新增進結果集

  • 如果nums[i]大於0,則三數之和必然無法等於0,結束迴圈

  • 如果 nums[i] == nums[i-1],則說明該數字重複,會導致結果重複,所以應該跳過

  • 當 sum == 0 時,nums[L] == nums[L+1] 則會導致結果重複,應該跳過,L++

  • 當 sum == 0 時,nums[R] == nums[R-1]則會導致結果重複,應該跳過,R−−

時間複雜度:O(n^2)

AC程式碼

//利用set集合去重,剛好卡著時間過,去重是可以通過手寫程式碼優化,不需要利用set集合。
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new LinkedList<>();
        Set<LinkedList<Integer>> st = new HashSet<>();
        Arrays.sort(nums);
        int index = 0;
        if(nums.length==0) return ans;
        while(true){
            if(nums[index] > 0 || index > nums.length - 3) break;
            int l = index+1;
            int r = nums.length-1;
            while(l < r){
                if(nums[index]+nums[l]+nums[r] == 0){
                    LinkedList<Integer> temp = new LinkedList<>();
                    temp.add(nums[index]);
                    temp.add(nums[l]);
                    temp.add(nums[r]);
                    if(st.add(temp)) ans.add(temp);
                    l++;
                    if(nums[l] == nums[l-1]) l++;
                }else if(nums[index]+nums[l]+nums[r] < 0){
                    l++;
                    if(nums[l] == nums[l-1]) l++;
                }
                else if(nums[index]+nums[l]+nums[r] > 0){
                    r--;
                    if(nums[r] == nums[r+1]) r--;
                }
            }
            index++;
        }
        return ans;
    }
}
//優化後的程式碼
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new LinkedList<>();
        Arrays.sort(nums);
        int index = 0;
        if(nums.length==0) return ans;
        while(true){
            if(index > nums.length - 3 || nums[index] > 0 ) break;
            int l = index+1;
            int r = nums.length-1;
            while(l < r){
                if(nums[index]+nums[l]+nums[r] == 0){
                    LinkedList<Integer> temp = new LinkedList<>();
                    temp.add(nums[index]);
                    temp.add(nums[l]);
                    temp.add(nums[r]);
                    ans.add(temp);
                    l++;
                    //去重
                    while(l<nums.length && nums[l] == nums[l-1]) l++;
                }else if(nums[index]+nums[l]+nums[r] < 0){
                    l++;
                    //去重
                    while(l < nums.length && nums[l] == nums[l-1]) l++;
                }
                else if(nums[index]+nums[l]+nums[r] > 0){
                    r--;
                    //去重
                    while(r > -1 && nums[r] == nums[r+1]) r--;
                }
            }
            index++;
            //去重
            while(index < nums.length && nums[index] == nums[index-1]) index++;
        }
        return ans;
    }
}

3.四數之和

題目連結

Leetcode18 四數之和

題目描述

解題思路

1.暴力,四重for迴圈

2.排序+雙指標

AC程式碼

//暴力法,四重for迴圈
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans = new LinkedList<>();
        Set<LinkedList> s = new HashSet<>();
        Arrays.sort(nums);
        for(int i = 0; i < nums.length; i++){
            for(int j = i+1; j < nums.length; j++){
                for(int k = j + 1; k < nums.length; k++){
                    for(int g = k + 1; g < nums.length; g++){
                        if(nums[i]+nums[j]+nums[k]+nums[g]==target){
                            LinkedList temp = new LinkedList<>();
                            temp.add(nums[i]);
                            temp.add(nums[j]);
                            temp.add(nums[k]);
                            temp.add(nums[g]);
                            if(s.add(temp)) ans.add(temp);
                        }
                    }
                }
            }
        }
        return ans;
    }
}

//排序+雙指標
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans = new LinkedList<>();
        Set<List<Integer>> hashset = new HashSet<>();
        Arrays.sort(nums);
        if(nums.length < 4) return ans;
        for(int i = 0; i < nums.length; i++){
            for(int j = i + 1; j < nums.length; j++){
                int l = j + 1;
                int r = nums.length-1;
                while(l < r){
                    if(nums[i]+nums[j]+nums[l]+nums[r] == target){
                        LinkedList temp = new LinkedList<>();
                        temp.add(nums[i]);
                        temp.add(nums[j]);
                        temp.add(nums[l]);
                        temp.add(nums[r]);
                        if(hashset.add(temp)) ans.add(temp);
                        l++;
                    }else if(nums[i]+nums[j]+nums[l]+nums[r] < target){
                        l++;
                    }else if(nums[i]+nums[j]+nums[l]+nums[r] > target){
                        r--;
                    }
                }
            }
        }
        return ans;
    }
}

n數之和

在三數和四數之和中,我們利用排序+雙指標都直接把暴力方法的時間複雜度降了一級,除了二數之和外,n數之和都可以採用排序+雙指標的解決方法。