圖解兩數之和:雙指標法

王亮hengg發表於2020-08-14

image

兩數之和是一道非常經典,也非常高頻的面試題,題目大意如下:

給定一個整數陣列nums 和一個目標值target,請你在該陣列中找出和為目標值的那兩個整數,並返回他們的陣列下標。
case:
給定 nums = [2, 1, 7, 11, 15], target = 9
因為 nums[0] + nums[2] = 2 + 7 = 9
所以返回 [0, 2]

之前我們探討了這個問題的暴力運演算法和雜湊表法,今天我們使用雙指標法來解決它。

太長不看版

  • 首先排序陣列;
  • 使用leftright兩個指標;
  • 比較targetleft值加right值的和,移動對應的指標;
  • 雙指標解法的時間複雜度取決於對應的排序演算法,空間複雜度為O(n)。

什麼是雙指標?

雙指標和快速排序、氣泡排序等具體演算法不同。它更接近於一種思(tào)路,一種使用兩個指標互相配合來儲存節點以便於運算的技巧。

雙指標法適用於陣列、連結串列等線性資料結構,常用的思路有:碰撞指標、滑動視窗、快慢指標等。

在兩數之和這個case中我們使用碰撞指標的方式來實現,其它兩種套路會在後續文章中介紹。

0.排序

所謂碰撞指標,是指在有序陣列中定義left(陣列起始位置)、right(陣列終止位置)兩個指標,在遍歷時根據對應條件的不同來判斷應該移動哪個指標,進而從陣列兩端遍歷陣列。

所以在兩數之和中我們需要先將目標陣列進行排序:


image


排序演算法的時間複雜度決定了整個計算的時間複雜度。因為雙指標遍歷的複雜度是O(n)。

1.建立雙指標

在排好序的陣列(以下簡稱陣列)兩端分別建立leftright指標:


image


2.左移右指標

此時left值與right值之和(以下簡稱sum)大於target,此時應該將right左移一位,減小sum使其更接近target

從這裡就可以看出,為什麼對有序陣列才適用碰撞指標。


image


3.繼續遍歷陣列

在這個case中我們需要繼續遍歷陣列,直到right指標指向7,此時sum小於target


image


4.右移左指標

與步驟2類似,當sum小於target時我們需要右移左指標,增加sum值使得兩者更加接近:


image


5.匹配成功!

在當前case中,left指向2時sumtarget相等,匹配成功!
此時返回left值和right值在原陣列中的下標即可:


image


6.完整示例程式碼

示例程式碼如下:


image


需要注意的是,由於JavaScript引用型別的特性,我們首先拷貝了nums,才使用Array.sort對拷貝陣列進行排序。

另外,對於nums=[1,2,2,3],target=4這種case,其期望的返回值是[1,2]而不是[1,1]或者[2,2]。所以這裡我們使用了Array.lastIndexOf()這個API。

小結

  • 採用碰撞雙指標進行運算;
  • 碰撞雙指標運算的時間複雜度取決於具體的排序演算法,空間複雜度為O(n);
  • 碰撞指標需要對陣列進行排序;
  • 排序時注意不要汙染原陣列;
  • 返回結果需要考慮陣列含有相同項;

再複習一下暴力運演算法和雜湊表法:

  • 雙層for迴圈暴力運算簡單直觀,時間複雜度O(n2)、空間複雜度O(1);
  • 雜湊表法時間複雜度和空間複雜度都是O(n);
  • 考察點是對雜湊表這種資料結構的熟悉程度;
  • 多一種解法就多一分勝算;
  • 整體難度不高。

一入JS深似海,希望這個專欄能在你乘風破浪的旅途中有所幫助。歡迎關注我的公眾號:「JS漫步指南」,更多精彩等待您發現!

image

相關文章