通常狀況下,遍歷數組(或者字符串)操做,都是採用單指針從前日後或者從後往前依次訪問數組(或者字符串)中的元素。 而對於如下狀況,只採用單指針處理,則會徒增時間複雜度和空間複雜度:前端
例如:找到兩個數使得它們相加之和等於目標數,採用單指針處理,則須要嵌套循環,使得時間複雜度增加爲 O(n^2);算法
再例如:翻轉數組,採用單指針處理,則須要額外內存空間,使得空間複雜度增加爲 O(n);數組
利用雙指針技巧則能夠優化上述解決方案:markdown
第一個例子:能夠先對採用數組進行排序預處理,再建立先後指針向中間遍歷,遍歷的時間複雜度爲 O(n),總體時間複雜度主要取決於排序算法,一般爲 O(nlogn);app
第二個列子:一個指針負責遍歷,另一個指針負責交換元素,從而使得空間複雜度爲 O(1);函數
雙指針沒有複雜的定義,總結起來主要處理兩類問題:oop
將嵌套循環轉化爲單循環問題;post
經過指針記錄狀態,從而優化空間複雜度;學習
下面的實戰分析會讓你感覺雙指針的威力。優化
給定一個已按照升序排列 的有序數組,找到兩個數使得它們相加之和等於目標數。函數應該返回這兩個下標值 index1和index2,其中index1 必須小於 index2。
這道題目採用單指針的作法只能經過嵌套循環枚舉全部兩數之和的方法來解決,時間複雜度爲 O(n^2)。
恰巧本題中的數組已是有序數組,那麼直接建立先後指針:
若是兩數以後大於 target,尾指針向前移動;
若是兩數之和小於 target,頭指針向後移動;
上述代碼利用雙指針技巧成功地將時間複雜度下降爲 O(n)。
const twoSum = (numbers, target) => {
const max = numbers.length
let start = 0
let end = max -1
while(start< end) {
const sum = numbers[start] + numbers[end]
if(sum === target)
{
return [start, end]
}
if(sum > target){
end --
continue
}
if(sum < target) {
start++
continue
}
}
}
// 這個文章裏的兩數之和是第一篇文章的升級版
// 時間複雜度:O(n)
// 空間複雜度: O(1) 比map 更加的高級
複製代碼
給定一個排序數組,你須要在 原地 刪除重複出現的元素,使得每一個元素只出現一次,返回移除後數組的新長度。
不要使用額外的數組空間,你必須在 原地 修改輸入數組 並在使用 O(1) 額外空間的條件下完成。
示例 1:給定數組 nums = [1,1,2],函數應該返回新的長度 2, 而且原數組 nums 的前兩個元素被修改成 1, 2。
你不須要考慮數組中超出新長度後面的元素。
示例 2:給定 nums = [0,0,1,1,1,2,2,3,3,4],函數應該返回新的長度 5, 而且原數組 nums 的前五個元素被修改成 0, 1, 2, 3, 4。
說明:
爲何返回數值是整數,但輸出的答案是數組呢?
請注意,輸入數組是以「引用」方式傳遞的,這意味着在函數裏修改輸入數組對於調用者是可見的。
解題思路: 使用快慢指針來記錄遍歷的座標。開始時這兩個指針都指向第一個數字,若是兩個指針指的數字相同,則快指針向前走一步。若是不一樣,則兩個指針都向前走一步,當快指針走完整個數組後,慢指針當前的座標加 1 就是數組中不一樣數字的個數。
const removeDuplicates = nums => {
const max = nums.length
if (max === 1) {
return nums
}
let slow = 0
for (let fast = 1; fast < max; fast++) {
if (nums[fast] !== nums[slow]) {
slow++
nums[slow] = nums[fast]
}
}
return slow + 1;
}
// 時間複雜度:O(n)
// 空間複雜度:O(1)
複製代碼
刷題打卡次日,選擇雙指針,學習了提高代碼效率的重要手段之一:前一次優化後的哈希map解法就是採用了空間換時間的方法。 可是雙指針能夠更加優化,可是前提是數組必須爲有序的,今天又刷了力扣的第26題,一塊兒加油哇~
若是你以爲這篇內容對你挺有有幫助的話: 點贊支持下吧,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓 -_-)關注公衆號給npy的前端祕籍,咱們一塊兒學習一塊兒進步。 以爲不錯的話,也能夠閱讀其餘文章(感謝朋友的鼓勵與支持🌹🌹🌹)
參考: 雙指針技巧Easy篇