[每日一題] 第十四題:和為s的兩個數字

DRose發表於2020-07-31

輸入一個遞增排序的陣列和一個數字s,在陣列中查詢兩個數,使得它們的和正好是s。如果有多對數字的和等於s,則輸出任意一對即可。

示例 1:

輸入:nums = [2,7,11,15], target = 9
輸出:[2,7] 或者 [7,2]

示例 2:

輸入:nums = [10,26,30,31,47,60], target = 40
輸出:[10,30] 或者 [30,10]

限制:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^6

方法一:我的題解

因為是遞增排序,我們就直接從陣列兩邊遍歷,定義一個 leftright,當兩數之和小於 target時,說明要右移左邊的數,當兩數之和大於 target 時,說明要左移右邊的數,當兩數之和等於 target 時,輸出結果。

注意:我的程式碼中沒有判斷如果不存在的情況,雖然透過了,但是是不對的,我沒有改正,當做反例,下面的一個題解是正例。

程式碼

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] result = new int[2]; 
        int left = 0;
        int right = nums.length - 1;
        while ((nums[left] + nums[right]) != target) {
            if ((nums[left] + nums[right]) < target) {
                left ++;
            } else {
                right--;
            }
        }
        result[0] = nums[left];
        result[1] = nums[right];
        return result;
    }
}

複雜度分析

  • 時間複雜度: 需要遍歷整個陣列,所以時間複雜度為 O(N)。
  • 空間複雜度: 額外定義了兩個變數 leftright,所以空間複雜度為 O(2)。

方法二:雙指標法(和我的思路一致,更詳細)

解題思路:

利用 HashMap 可以透過遍歷陣列找到數字組合,時間和空間複雜度均為 O(N);
注意本題的 nums 是 排序陣列,因此可使用 雙指標法 將空間複雜度降至 O(1)。

演算法流程:

  1. 初始化: 雙指標 i,j 分別指向陣列 nums 的左右兩端(俗稱對撞雙指標)。

  2. 迴圈搜尋: 當雙指標相遇時跳出:

    1. 計算和 s = nums[i] + nums[j];
    2. 若 s > target,則指標 j 向左移動,即執行 j = j - 1;
    3. 若 s < target,則指標 i 向右移動,即執行 i = i + 1;
    4. 若 s = target,立即返回陣列 [nums[i], nums[j]];
  3. 返回空陣列,代表無和為 target 的數字組合。

正確性證明:

記每個狀態為 S(i,j) ,即 S(i,j)=nums[i]+nums[j] 。假設 S(i,j)<target ,則執行 i=i+1 ,即狀態切換至 S(i+1,j) 。

  • 狀態 S(i,j) 切換至 S(i+1,j) ,則會消去一行元素,相當於 消去了狀態集合 {S(i,i+1),S(i,i+2),…,S(i,j−2),S(i,j−1),S(i,j) } 。(由於雙指標都是向中間收縮,因此這些狀態之後不可能再遇到)。
  • 由於 nums 是排序陣列,因此這些 消去的狀態 都一定滿足 S(i,j)<target ,即這些狀態都 不是解 。
  • 結論: 以上分析已證明 “每次指標 i 的移動操作,都不會導致解的丟失” ,即指標 i 的移動操作是 安全的 ;同理,對於指標 j 可得出同樣推論;因此,此雙指標法是正確的。

[每日一題] 第十四題:和為s的兩個數字

程式碼

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int i = 0, j = nums.length - 1;
        while(i < j) {
            int s = nums[i] + nums[j];
            if(s < target) i++;
            else if(s > target) j--;
            else return new int[] { nums[i], nums[j] };
        }
        return new int[0];
    }
}

複雜度分析

  • 時間複雜度 O(N) : N 為陣列 nums 的長度;雙指標共同線性遍歷整個陣列。
  • 空間複雜度 O(1) : 變數 i, j 使用常數大小的額外空間。

題解來源

作者:jyd
連結:leetcode-cn.com/problems/he-wei-sd...
來源:力扣(LeetCode)

來源:力扣(LeetCode)
連結:leetcode-cn.com/problems/he-wei-sd...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章