1. 程式人生 > 其它 >演算法學習100天——10 雙指標

演算法學習100天——10 雙指標

題目地址(167. 兩數之和 II - 輸入有序陣列)

https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/

題目描述

給你一個下標從 1 開始的整數陣列 numbers ,該陣列已按 非遞減順序排列  ,請你從陣列中找出滿足相加之和等於目標數 target 的兩個數。如果設這兩個數分別是 numbers[index1] 和 numbers[index2] ,則 1 <= index1 < index2 <= numbers.length 。
以長度為 2 的整數陣列 [index1, index2] 的形式返回這兩個整數的下標 index1 和 index2。
你可以假設每個輸入 只對應唯一的答案 ,而且你 不可以 重複使用相同的元素。
你所設計的解決方案必須只使用常量級的額外空間。

示例 1:
輸入:numbers = [2,7,11,15], target = 9
輸出:[1,2]
解釋:2 與 7 之和等於目標數 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

示例 2:
輸入:numbers = [2,3,4], target = 6
輸出:[1,3]
解釋:2 與 4 之和等於目標數 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。

示例 3:
輸入:numbers = [-1,0], target = -1
輸出:[1,2]
解釋:-1 與 0 之和等於目標數 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。 

提示:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 非遞減順序 排列
-1000 <= target <= 1000
僅存在一個有效答案

解題思路

這個題和1.兩數之和很像,但是這題返回的是兩個數,就用到了昨天的一開始的思路—雙指標

利用雙指標,可以O(N)時間複雜度解決問題

優化:雙指標遍歷,最差是O(N),原理是選定一個數,查詢另一個滿足條件的數,既然是查詢,就想到了二分法,所以可以每次二分查詢一個數,判斷是否滿足條件,再根據情況調整

程式碼(雙指標)

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        for(int left = 0, right = numbers.length - 1; left < right; ){
            if(numbers[left] + numbers[right] == target){
                return new int[]{left + 1, right + 1};
            }
            if(numbers[left] + numbers[right] < target){
                left ++;
            }else{
                right --;
            }
        }
        return null;
    }
}

結果

執行用時:1 ms, 在所有 Java 提交中擊敗了75.29%的使用者

記憶體消耗:44.5 MB, 在所有 Java 提交中擊敗了5.12%的使用者

程式碼(二分查詢優化後)

class Solution {
    public int[] twoSum(int[] numbers, int target) {
       for(int left = 0, right = numbers.length - 1; left < right; ){
            int m = ((right - left) >> 1) + left;
            if(numbers[m] + numbers[right] < target){
                left = m + 1;
            }else if(numbers[left] + numbers[m] > target){
                right = m - 1;
            }else if(numbers[left] + numbers[right] < target){
                left ++;
            }else if(numbers[left] + numbers[right] > target){
                right --;
            }else{
                return new int[]{left + 1, right + 1};
            }
        }
        return null;
    }
}

結果

執行用時:0 ms, 在所有 Java 提交中擊敗了100.00%的使用者

記憶體消耗:44.1 MB, 在所有 Java 提交中擊敗了14.95%的使用者