RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

快慢指針的常見算法介紹

jf_78858299 ? 來(lái)源:labuladong ? 作者:labuladong ? 2023-04-19 10:57 ? 次閱讀

我認(rèn)為雙指針技巧還可以分為兩類,一類是「快慢指針」,一類是「左右指針」。前者解決主要解決鏈表中的問題,比如典型的判定鏈表中是否包含環(huán);后者主要解決數(shù)組(或者字符串)中的問題,比如二分查找。

一、快慢指針的常見算法

快慢指針一般都初始化指向鏈表的頭結(jié)點(diǎn) head,前進(jìn)時(shí)快指針 fast 在前,慢指針 slow 在后,巧妙解決一些鏈表中的問題。

1 、判定鏈表中是否含有環(huán)

這應(yīng)該屬于鏈表最基本的操作了,如果讀者已經(jīng)知道這個(gè)技巧,可以跳過。

單鏈表的特點(diǎn)是每個(gè)節(jié)點(diǎn)只知道下一個(gè)節(jié)點(diǎn),所以一個(gè)指針的話無(wú)法判斷鏈表中是否含有環(huán)的。

如果鏈表中不含環(huán),那么這個(gè)指針最終會(huì)遇到空指針 null 表示鏈表到頭了,這還好說,可以判斷該鏈表不含環(huán)。

boolean hasCycle(ListNode head) {
    while (head != null)
        head = head.next;
    return false;
}

但是如果鏈表中含有環(huán),那么這個(gè)指針就會(huì)陷入死循環(huán),因?yàn)?a target="_blank">環(huán)形數(shù)組中沒有 null 指針作為尾部節(jié)點(diǎn)。

經(jīng)典解法就是用兩個(gè)指針,一個(gè)每次前進(jìn)兩步,一個(gè)每次前進(jìn)一步。如果不含有環(huán),跑得快的那個(gè)指針最終會(huì)遇到 null,說明鏈表不含環(huán);如果含有環(huán),快指針最終會(huì)超慢指針一圈,和慢指針相遇,說明鏈表含有環(huán)。

圖片

2 、已知鏈表中含有環(huán),返回這個(gè)環(huán)的起始位置

圖片

這個(gè)問題其實(shí)不困難,有點(diǎn)類似腦筋急轉(zhuǎn)彎,先直接看代碼:


圖片

可以看到,當(dāng)快慢指針相遇時(shí),讓其中任一個(gè)指針重新指向頭節(jié)點(diǎn),然后讓它倆以相同速度前進(jìn),再次相遇時(shí)所在的節(jié)點(diǎn)位置就是環(huán)開始的位置。這是為什么呢?

第一次相遇時(shí),假設(shè)慢指針 slow 走了 k 步,那么快指針 fast 一定走了 2k 步,也就是說比 slow 多走了 k 步(也就是環(huán)的長(zhǎng)度)。

圖片

設(shè)相遇點(diǎn)距環(huán)的起點(diǎn)的距離為 m,那么環(huán)的起點(diǎn)距頭結(jié)點(diǎn) head 的距離為 k - m,也就是說如果從 head 前進(jìn) k - m 步就能到達(dá)環(huán)起點(diǎn)。

巧的是,如果從相遇點(diǎn)繼續(xù)前進(jìn) k - m 步,也恰好到達(dá)環(huán)起點(diǎn)。

圖片

所以,只要我們把快慢指針中的任一個(gè)重新指向 head,然后兩個(gè)指針同速前進(jìn),k - m 步后就會(huì)相遇,相遇之處就是環(huán)的起點(diǎn)了。

3 、尋找鏈表的中點(diǎn)

類似上面的思路,我們還可以讓快指針一次前進(jìn)兩步,慢指針一次前進(jìn)一步,當(dāng)快指針到達(dá)鏈表盡頭時(shí),慢指針就處于鏈表的中間位置。

ListNode slow, fast;
slow = fast = head;
while (fast != null && fast.next != null) {
    fast = fast.next.next;
    slow = slow.next;
}
// slow 就在中間位置
return slow;

當(dāng)鏈表的長(zhǎng)度是奇數(shù)時(shí),slow 恰巧停在中點(diǎn)位置;如果長(zhǎng)度是偶數(shù),slow 最終的位置是中間偏右:

圖片

尋找鏈表中點(diǎn)的一個(gè)重要作用是對(duì)鏈表進(jìn)行歸并排序。

回想數(shù)組的歸并排序:求中點(diǎn)索引遞歸地把數(shù)組二分,最后合并兩個(gè)有序數(shù)組。對(duì)于鏈表,合并兩個(gè)有序鏈表是很簡(jiǎn)單的,難點(diǎn)就在于二分。

但是現(xiàn)在你學(xué)會(huì)了找到鏈表的中點(diǎn),就能實(shí)現(xiàn)鏈表的二分了。關(guān)于歸并排序的具體內(nèi)容本文就不具體展開了。

4 、尋找鏈表的倒數(shù)第 k 個(gè)元素

我們的思路還是使用快慢指針,讓快指針先走 k 步,然后快慢指針開始同速前進(jìn)。這樣當(dāng)快指針走到鏈表末尾 null 時(shí),慢指針?biāo)诘奈恢镁褪堑箶?shù)第 k 個(gè)鏈表節(jié)點(diǎn)(為了簡(jiǎn)化,假設(shè) k 不會(huì)超過鏈表長(zhǎng)度):

ListNode slow, fast;
slow = fast = head;
while (k-- > 0) 
    fast = fast.next;

while (fast != null) {
    slow = slow.next;
    fast = fast.next;
}
return slow;

二、左右指針的常用算法

左右指針在數(shù)組中實(shí)際是指兩個(gè)索引值,一般初始化為 left = 0, right = nums.length - 1 。

1 、二分查找

前文 [二分查找算法詳解] 有詳細(xì)講解,這里只寫最簡(jiǎn)單的二分算法,旨在突出它的雙指針特性:

圖片

2 、兩數(shù)之和

直接看一道 LeetCode 題目吧:

圖片

只要數(shù)組有序,就應(yīng)該想到雙指針技巧。這道題的解法有點(diǎn)類似二分查找,通過調(diào)節(jié) left 和 right 可以調(diào)整 sum 的大?。?/p>

圖片

3 、反轉(zhuǎn)數(shù)組

void reverse(int[] nums) {
    int left = 0;
    int right = nums.length - 1;
    while (left < right) {
        // swap(nums[left], nums[right])
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
        left++; right--;
    }
}

4 、滑動(dòng)窗口算法

這也許是雙指針技巧的最高境界了,如果掌握了此算法,可以解決一大類子字符串匹配的問題,不過「滑動(dòng)窗口」算法比上述的這些算法稍微復(fù)雜些。

幸運(yùn)的是,這類算法是有框架模板的,下篇文章就準(zhǔn)備講解「滑動(dòng)窗口」算法模板,幫大家秒殺幾道 LeetCode 子串匹配的問題。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 算法
    +關(guān)注

    關(guān)注

    23

    文章

    4607

    瀏覽量

    92826
  • 初始化
    +關(guān)注

    關(guān)注

    0

    文章

    50

    瀏覽量

    11850
  • 單鏈表
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    6918
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    淺析函數(shù)指針指針函數(shù)及其應(yīng)用

    什么是指針?相信大家對(duì)這個(gè)問題其實(shí)并不陌生,對(duì)指針的概念也不會(huì)很模糊,在這里我也大概介紹一下。
    發(fā)表于 03-08 13:17 ?262次閱讀

    函數(shù)指針指針函數(shù)的概念

    不少朋友會(huì)混淆“函數(shù)指針”和“指針函數(shù)”這兩個(gè)概念,本文詳細(xì)介紹一下。
    發(fā)表于 03-09 10:49 ?1192次閱讀

    常見圖像傳統(tǒng)處理算法是什么?

    常見圖像傳統(tǒng)處理算法是什么?
    發(fā)表于 09-28 08:58

    幾種常見的濾波算法

    **幾種常見的濾波算法**限幅濾波算法(程序判斷濾波算法)顧名思義,就是單純用程序來(lái)處理輸入數(shù)據(jù)In_data,通過對(duì)相鄰兩次數(shù)據(jù)取誤差的絕對(duì)值 |error|,通過經(jīng)驗(yàn)判斷兩次In_
    發(fā)表于 01-11 06:37

    過程間指針分析算法的改進(jìn)

    指針分析對(duì)于使用C語(yǔ)言編制程序的數(shù)據(jù)流分析有著重要的意義。該文介紹指針問題的復(fù)雜度、指針分析算法的分類以及
    發(fā)表于 04-02 09:05 ?9次下載

    C語(yǔ)言入門教程-指針常見錯(cuò)誤

    指針常見錯(cuò)誤 錯(cuò)誤 1:未初始化的指針一個(gè)最易犯的指針錯(cuò)誤是試圖引用未初始化(因而指向的是無(wú)效地址)的指針。例如: int*p; *
    發(fā)表于 07-29 11:47 ?1121次閱讀

    C語(yǔ)言中指針介紹非常詳細(xì)

    C語(yǔ)言中指針介紹非常詳細(xì) C語(yǔ)言中指針介紹非常詳細(xì)
    發(fā)表于 12-25 10:39 ?57次下載

    C語(yǔ)言指針函數(shù)和函數(shù)指針詳細(xì)介紹

    C語(yǔ)言指針函數(shù)和函數(shù)指針詳細(xì)介紹。。。。。。。
    發(fā)表于 03-04 15:27 ?5次下載

    再再論指針

    關(guān)于指針的幾個(gè)關(guān)鍵概念及常見問題。
    發(fā)表于 04-05 15:53 ?0次下載

    c語(yǔ)言函數(shù)指針定義,指針函數(shù)和函數(shù)指針的區(qū)別

     往往,我們一提到指針函數(shù)和函數(shù)指針的時(shí)候,就有很多人弄不懂。下面就由小編詳細(xì)為大家介紹C語(yǔ)言中函數(shù)指針,指針函數(shù)和函數(shù)
    發(fā)表于 11-16 15:18 ?3624次閱讀

    理解函數(shù)指針、函數(shù)指針數(shù)組、函數(shù)指針數(shù)組的指針

    理解函數(shù)指針、函數(shù)指針數(shù)組、函數(shù)指針數(shù)組的指針
    的頭像 發(fā)表于 06-29 15:38 ?1.5w次閱讀
    理解函數(shù)<b class='flag-5'>指針</b>、函數(shù)<b class='flag-5'>指針</b>數(shù)組、函數(shù)<b class='flag-5'>指針</b>數(shù)組的<b class='flag-5'>指針</b>

    快慢指針、左右指針常見算法

    技巧秒殺 5 道算法題。 其實(shí),鼎鼎有名的「滑動(dòng)窗口算法」就是一種雙指針技巧,我們之前的爆文我寫了套框架,把滑動(dòng)窗口算法變成了默寫題就有這么一段: 我把雙
    的頭像 發(fā)表于 11-26 14:09 ?2470次閱讀

    四種常見的圖像濾波算法介紹

    濾波算法,并附上源碼,包括自適應(yīng)中值濾波、高斯濾波、雙邊濾波和導(dǎo)向?yàn)V波。 前言 本文介紹四種常見的圖像濾波算法,并附上源碼。圖像濾波是一種非常重要的圖像處理技術(shù),現(xiàn)在大火的卷積神經(jīng)網(wǎng)絡(luò)
    的頭像 發(fā)表于 02-15 09:50 ?9995次閱讀

    數(shù)組相關(guān)的雙指針算法

    對(duì)于單鏈表來(lái)說,大部分技巧都屬于快慢指針,前文 單鏈表的六大解題套路 都涵蓋了,比如鏈表環(huán)判斷,倒數(shù)第K個(gè)鏈表節(jié)點(diǎn)等問題,它們都是通過一個(gè)fast快指針和一個(gè)slow慢指針配合完成任務(wù)
    的頭像 發(fā)表于 04-28 16:22 ?1891次閱讀

    電機(jī)轉(zhuǎn)速快慢怎么調(diào) 電機(jī)快慢是靠什么控制的 電機(jī)轉(zhuǎn)速的計(jì)算公式

     電機(jī)快慢的控制通常是通過改變電源電壓或電流來(lái)實(shí)現(xiàn)的。具體來(lái)說,電機(jī)的轉(zhuǎn)速與電源電壓或電流成正比,因此通過調(diào)節(jié)電源電壓或電流可以實(shí)現(xiàn)電機(jī)的快慢控制。
    發(fā)表于 03-19 14:24 ?2.4w次閱讀
    電機(jī)轉(zhuǎn)速<b class='flag-5'>快慢</b>怎么調(diào) 電機(jī)<b class='flag-5'>快慢</b>是靠什么控制的 電機(jī)轉(zhuǎn)速的計(jì)算公式
    RM新时代网站-首页