雙指標技巧總結

2022-07-03 23:18:21 字數 3545 閱讀 9256

141.環形鍊錶

141.環形鍊錶ii

167.兩數之和 ii - 輸入有序陣列

-----------

我把雙指標技巧再分為兩類,一類是「快慢指標」,一類是「左右指標」。前者解決主要解決鍊錶中的問題,比如典型的判定鍊錶中是否包含環;後者主要解決陣列(或者字串)中的問題,比如二分查詢。

快慢指標一般都初始化指向鍊錶的頭結點 head,前進時快指標 fast 在前,慢指標 slow 在後,巧妙解決一些鍊錶中的問題。

1、判定鍊錶中是否含有環

這應該屬於鍊錶最基本的操作了,如果讀者已經知道這個技巧,可以跳過。

單鏈表的特點是每個節點只知道下乙個節點,所以乙個指標的話無法判斷鍊錶中是否含有環的。

如果鍊錶中不含環,那麼這個指標最終會遇到空指標 null 表示鍊錶到頭了,這還好說,可以判斷該鍊錶不含環。

boolean hascycle(listnode head)
但是如果鍊錶中含有環,那麼這個指標就會陷入死迴圈,因為環形陣列中沒有 null 指標作為尾部節點。

經典解法就是用兩個指標,乙個跑得快,乙個跑得慢。如果不含有環,跑得快的那個指標最終會遇到 null,說明鍊錶不含環;如果含有環,快指標最終會超慢指標一圈,和慢指標相遇,說明鍊錶含有環。

ps:我認真寫了 100 多篇原創,手把手刷 200 道力扣題目,全部發布在 labuladong的演算法小抄,持續更新。建議收藏,按照我的文章順序刷題,掌握各種演算法套路後投再入題海就如魚得水了。

boolean hascycle(listnode head) 

return false;

}

2、已知鍊錶中含有環,返回這個環的起始位置

這個問題一點都不困難,有點類似腦筋急轉彎,先直接看**:

listnode detectcycle(listnode head) 

// 上面的**類似 hascycle 函式

slow = head;

while (slow != fast)

return slow;

}

可以看到,當快慢指標相遇時,讓其中任乙個指標指向頭節點,然後讓它倆以相同速度前進,再次相遇時所在的節點位置就是環開始的位置。這是為什麼呢?

第一次相遇時,假設慢指標 slow 走了 k 步,那麼快指標 fast 一定走了 2k 步,也就是說比 slow 多走了 k 步(也就是環的長度)。

設相遇點距環的起點的距離為 m,那麼環的起點距頭結點 head 的距離為 k - m,也就是說如果從 head 前進 k - m 步就能到達環起點。

巧的是,如果從相遇點繼續前進 k - m 步,也恰好到達環起點。

所以,只要我們把快慢指標中的任乙個重新指向 head,然後兩個指標同速前進,k - m 步後就會相遇,相遇之處就是環的起點了。

3、尋找鍊錶的中點

類似上面的思路,我們還可以讓快指標一次前進兩步,慢指標一次前進一步,當快指標到達鍊錶盡頭時,慢指標就處於鍊錶的中間位置。

while (fast != null && fast.next != null) 

// slow 就在中間位置

return slow;

當鍊表的長度是奇數時,slow 恰巧停在中點位置;如果長度是偶數,slow 最終的位置是中間偏右:

尋找鍊錶中點的乙個重要作用是對鍊錶進行歸併排序。

回想陣列的歸併排序:求中點索引遞迴地把陣列二分,最後合併兩個有序陣列。對於鍊錶,合併兩個有序鍊錶是很簡單的,難點就在於二分。

但是現在你學會了找到鍊錶的中點,就能實現鍊錶的二分了。關於歸併排序的具體內容本文就不具體展開了。

4、尋找鍊錶的倒數第 k 個元素

我們的思路還是使用快慢指標,讓快指標先走 k 步,然後快慢指標開始同速前進。這樣當快指標走到鍊錶末尾 null 時,慢指標所在的位置就是倒數第 k 個鍊錶節點(為了簡化,假設 k 不會超過鍊錶長度):

listnode slow, fast;

slow = fast = head;

while (k-- > 0)

fast = fast.next;

while (fast != null)

return slow;

ps:我認真寫了 100 多篇原創,手把手刷 200 道力扣題目,全部發布在 labuladong的演算法小抄,持續更新。建議收藏,按照我的文章順序刷題,掌握各種演算法套路後投再入題海就如魚得水了。

左右指標在陣列中實際是指兩個索引值,一般初始化為 left = 0, right = nums.length - 1 。

1、二分查詢

前文「二分查詢」有詳細講解,這裡只寫最簡單的二分演算法,旨在突出它的雙指標特性:

int binarysearch(int nums, int target) 

return -1;

}

2、兩數之和直接看一道 leetcode 題目吧:

只要陣列有序,就應該想到雙指標技巧。這道題的解法有點類似二分查詢,通過調節 left 和 right 可以調整 sum 的大小:

int twosum(int nums, int target) ;

} else if (sum < target) else if (sum > target)

}return new int;

}

3、反轉陣列

void reverse(int nums) 

}

4、滑動視窗演算法這也許是雙指標技巧的最高境界了,如果掌握了此演算法,可以解決一大類子字串匹配的問題,不過「滑動視窗」稍微比上述的這些演算法複雜些。

幸運的是,這類演算法是有框架模板的,而且這篇文章就講解了「滑動視窗」演算法模板,幫大家秒殺幾道 leetcode 子串匹配的問題。

_____________

雙指標技巧總結

我把雙指標技巧再分為兩類,一類是 快慢指標 一類是 左右指標 前者解決主要解決鍊錶中的問題,比如典型的判定鍊錶中是否包含環 後者主要解決陣列 或者字串 中的問題,比如二分查詢。一 快慢指標的常見演算法 快慢指標一般都初始化指向鍊錶的頭結點 head,前進時快指標 fast 在前,慢指標 slow 在...

雙指標技巧

我們通過迭代陣列來解決一些問題。通常,我們只使用從第乙個元素開始並在最後乙個元素結束的乙個指標來進行迭代。但是,有時候,我們可能需要同時使用兩個指標來進行迭代。例如 翻轉陣列中的元素 void reverse vector nums 總之,使用雙指標技巧的典型場景之一是你想要從兩端向中間迭代陣列。這...

雙指標技巧彙總

源自 labuladong 鍊錶指標陣列題,用雙指標別猶豫 快慢指標最神奇,鍊錶操作無壓力 歸併排序找中點,鍊錶成環搞判定 左右指標很常見,左右兩端向前行 反轉陣列要靠他,二分查詢是弟弟 2.已知鍊錶中含有環,返回這個環的起始位置 3.尋找鍊錶的中點 4.尋找鍊錶的倒數第 k 個元素 二 左右指標 ...