LintCode 533. 兩數和的最接近值

原題

第一步,萬年不變的查錯。如果給的array是null或不夠兩個數,直接return 0

  public int twoSumClosest(int[] nums, int target) {
      if (nums == null || nums.length < 2) {
          return 0;
      }
      ...
  }

看題,第一步想到暴力解法,即找到每一對數字的和,再從這一堆和里面,找出與target最接近的(打擂臺)。這種方式為O(n^2),因為每一個數字都要和除自己以外的數字算一次。怎樣進行優化呢?題里有提示,挑戰用O(nlogn)來解。O(nlogn)大部分就是排序,因為排序最低就是O(nlogn)。所以想到對array排序。

  Arrays.sort(nums);

然后就是怎么利用一個已經排好序的數列。首先要有一個最低的差,minSumDiff。初始化為最大值,以為一會要用它來比小,所以第一次不管是什么數字,都不會比它大。再來兩個pointer,一左一右。

  int minSumDiff = Integer.MAX_VALUE;
  int left = 0;
  int right = nums.length - 1;

左右兩個pointer同時開始向中間移動,如果需要數字之和變小,那就右邊往左移。找到當前兩個pointer指向的數字之和sum,以及跟target的差sumDiff

  while (left < right)  {
    int sum = nums[left] + nums[right];
    if (sum == target) {
        return 0;
    }
    int sumDiff = Math.abs(target - sum);
    ...
  }

這里有可能出現一個edge case,sum跟target一樣,即它們的差為0。當這個時候,我加了一個if statement,如果出現就直接返回,既然找到一樣的了,后面就沒有繼續遍歷的必要了。這里加不加都可以。如果數列里出現一個和跟target一樣的,那么加了就比不加好。相反,如果沒有,加了就不如不加。可以問面試官那種可能更大一點。

如果需要數字之和變大,那就左邊往右移。移動的過程中,不斷的進行打擂臺,對比當前最低的接近差,如果比當前最低的低,那就把最低的改成現在的差。

      minSumDiff = Math.min(minSumDiff, sumDiff);

然后如果當前的和小于target,那我們就去找下一個大一點的數,即右邊pointer往左移。如果當前的和大于target,那我們就去找下一個小一點的數,即左邊的pointer往右移。

      if (sum < target) {
        left++;
      } else {
        right--;
      }

最后,返回當前最低的差即可。

  return minSumDiff;

完整的code

public class Solution {
    /*
     * @param nums: an integer array
     * @param target: An integer
     * @return: the difference between the sum and the target
     */
    public int twoSumClosest(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        Arrays.sort(nums);
        int minSumDiff = Integer.MAX_VALUE;
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int sum = nums[left] + nums[right];
            if (sum == target) {
                return 0;
            }
            int sumDiff = Math.abs(target - sum);
            minSumDiff = Math.min(sumDiff, minSumDiff);
            if (sum < target) {
                left++;
            } else {
                right--;
            }
        }
        
        return minSumDiff;
    }
}

分析

時間復雜度

對array進行排序,為O(nlogn)。兩個pointer遍歷,為O(n)。所以總共的時間復雜度是O(nlogn)。

空間復雜度

只有個別的單個變量,所以空間復雜度是O(1)。

這道題我的思路和九章一樣。應該是最優解。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,768評論 0 33
  • 課程介紹 先修課:概率統計,程序設計實習,集合論與圖論 后續課:算法分析與設計,編譯原理,操作系統,數據庫概論,人...
    ShellyWhen閱讀 2,349評論 0 3
  • 排序算法說明 (1)排序的定義:對一序列對象根據某個關鍵字進行排序; 輸入:n個數:a1,a2,a3,…,an 輸...
    code武閱讀 675評論 0 0
  • 霧氣氤氳 她卻看到一條船 滿載靈魂 不揚帆 她向別人提起 回憶鮮紅色畫板 無知者無感 所道既然 依舊孤身一人 固執...
    一木丸閱讀 162評論 0 1
  • 引言 一開始聽說閉包Closures這個詞是來自于Objective-C中的Block,乍一眼看起來特別像函數fu...
    Mr杰杰閱讀 363評論 0 2