1. 程式人生 > >Leetcode 167. 兩數之和 II - 輸入有序陣列 Java&Python

Leetcode 167. 兩數之和 II - 輸入有序陣列 Java&Python

給定一個已按照升序排列 的有序陣列,找到兩個數使得它們相加之和等於目標數。

函式應該返回這兩個下標值 index1 和 index2,其中 index1 必須小於 index2

說明:

  • 返回的下標值(index1 和 index2)不是從零開始的。
  • 你可以假設每個輸入只對應唯一的答案,而且你不可以重複使用相同的元素。

示例:

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

在這裡想和大家分享一下基本的解題思路,誠然這道題目非常簡單,但是當遇到難題的時候,一個好的解題思路或許會為我們找到突破點。這道題用暴力解法,兩次迴圈便可得出答案,但是提交給leetcode應該會timeout,因為O(n2)基本的演算法在資料量太大的時候,會非常耗時,那麼怎麼降低時間複雜度呢,結合題目,我們可以看到陣列是有序,既然是有序的陣列,是否可以用二分查詢來尋找target-number[i]呢?

public int[] twoSum(int[] numbers, int target) {

        int[] res = new int[2];

        for (int i = 0; i < numbers.length; i++) {
            int pos = findIndex(numbers, i + 1, numbers.length - 1, target - numbers[i]);
            if (pos >= 0) {
                res[0] = i + 1;
                res[1] = pos + 1;
            }
        }

        return res;
    }

    private int findIndex(int[] numbers, int start, int end, int target) {
        while (start <= end) {

            int mid = start + (end - start) / 2;

            if (numbers[mid] == target) {
                return mid;
            } else if (numbers[mid] < target) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }
        }
        return -1;
    }

這樣降到O(nlogn)便可以AC了,那麼還有更好的解決方案嗎,在遍歷一次的情況下,便可以得到結果,這裡可以使用對撞指標來解決,分別使兩個指標指向首尾,如果相加等於,便找到了對應的索引,如果小於需要右移左指標,大於便左移右指標。

public int[] twoSum(int[] numbers, int target) {

        int l = 0, r = numbers.length - 1;

        while (l < r) {
            if (numbers[l] + numbers[r] == target) {
                return new int[]{l + 1, r + 1};
            } else if (numbers[l] + numbers[r] < target) {
                l++;
            } else {
                r--;
            }
        }

        return new int[2];
    }

下面是Python實現

class Solution:
    def twoSum(self, numbers, target):
        """
        :type numbers: List[int]
        :type target: int
        :rtype: List[int]
        """
        i = 0
        j = len(numbers) - 1

        while i < j:
            if numbers[i] + numbers[j] == target:
                return [i + 1, j + 1]
            elif numbers[i] + numbers[j] < target:
                i += 1
            else:
                j -= 1

關於對撞指標,類似的題目還有Leetcode125號問題:驗證迴文串, 345號問題 反轉字串中的母音字母等,有興趣的同學也可以做做這些題目。