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

LeetCode-167. 兩數之和 II - 輸入有序陣列

題目

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

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

說明:

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

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

解題

方法一 : 二分查詢

因為陣列是有序的, 所以可以使用二分查詢的方式解決, 遍歷陣列, 在遍歷i元素時, 在[i + 1…nums.length - 1]的區間查詢等於target - nums[i]的元素, 程式碼如下:

class Solution {
    
    // 二分查詢, 在numbers[l..r]的區間查詢值為target的元素, 返回下標索引, 找不到符合條件的元素返回-1
    private int bs(int[] numbers, int target, int l, int r){
        if(l > r){
            return -1;
        }
if(l == r){ if(numbers[l] == target){ return r; } else { return -1; } } int mid = (r - l ) / 2 + l; if(target == numbers[mid]){ return mid; } else if (target <
numbers[mid]){ return bs(numbers, target, l, mid - 1); } else { return bs(numbers, target, mid + 1, r); } } public int[] twoSum(int[] numbers, int target) { int[] indexs = new int[2]; for(int i = 0; i < numbers.length; i++){ int tempTarget = target - numbers[i]; int secondIndex = bs(numbers, tempTarget, i + 1, numbers.length - 1); if(secondIndex != -1){ // 下標從1開始, 所以陣列下標都要加上1 indexs[0] = i + 1; indexs[1] = secondIndex + 1; break; } } return indexs; } }

方法二 : 雙指標

  • 使用兩個變數l,r分別指向陣列的兩側, 初始化l = 0, r = nums.length -1
  • 如果nums[l] + nums[r] == target就表示找到這兩個和為target的兩個數字了
  • 如果nums[l] + nums[r] < target就表示l小了 , l++即可
  • 如果nums[l] + nums[r] > target就表示r打了, r–即可
  • 以上條件都是基於陣列有序的情況下才成立, 剛好本題陣列就是有序的, 程式碼如下:
class Solution {
        
    public int[] twoSum(int[] numbers, int target) {
        int l = 0;
        int 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 null;      
    }
}

雙指標的時間複雜度是O(logn), 高於二分查詢