圖解兩數之和:雙指針法

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中咱們使用碰撞指針的方式來實現,其它兩種套路會在後續文章中介紹。spa

0.排序

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

因此在兩數之和中咱們須要先將目標數組進行排序:指針


image


排序算法的時間複雜度決定了整個計算的時間複雜度。由於雙指針遍歷的複雜度是O(n)。code

1.建立雙指針

在排好序的數組(如下簡稱數組)兩端分別建立leftright指針:blog


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