從0學(xué)算法:雙指針

??雙指針,指的是在遍歷對(duì)象的過(guò)程中元莫,不是普通的使用單個(gè)指針進(jìn)行訪問(wèn)赖阻。而是使用兩個(gè)指針采用不同的方式進(jìn)行移動(dòng),從而達(dá)到我們的目的踱蠢。

??單指針就是我們常用的for循環(huán)火欧,使用一個(gè)指針從容器的一端遍歷至另一端,相對(duì)比較好理解茎截。如下圖:
單指針.png

??雙指針?biāo)惴ū粡V泛的用來(lái)解決數(shù)組苇侵、鏈表相關(guān)的問(wèn)題,除此之外二分查找和滑動(dòng)窗口等算法也用到了雙指針?biāo)惴ㄆ笮俊3R?jiàn)的雙指針有以下幾種用法:

1.快慢指針
2.固定間距指針
3.對(duì)撞指針
下面榆浓,我將針對(duì)這三種用法來(lái)舉例說(shuō)明。

1.快慢指針

??快慢指針指兩個(gè)指針步長(zhǎng)不同撕攒。
??經(jīng)典用法就是用于檢測(cè)鏈表是否有環(huán)陡鹃,例如LeetCode 141 Easy 環(huán)形鏈表烘浦。這道題我們除了可以用HashSet判斷一個(gè)節(jié)點(diǎn)是否被訪問(wèn)過(guò)以外,也可以用快慢指針來(lái)解決:如果鏈表存在環(huán)萍鲸,那么快指針終將追上慢指針闷叉。
??題目描述和官方解法如下:

LeetCode 141 環(huán)形鏈表

public boolean hasCycle(ListNode head) {
    if (head == null || head.next == null) {
        return false;
    }
    ListNode slow = head;
    ListNode fast = head.next;
    while (slow != fast) {
        if (fast == null || fast.next == null) {
            return false;
        }
        slow = slow.next;
        fast = fast.next.next;
    }
    return true;
}

2.固定間距指針

??兩個(gè)指針距離一定的距離,步長(zhǎng)相同
??經(jīng)典用法就是用于解決滑動(dòng)窗口脊阴,或者一次遍歷獲取鏈表的倒數(shù)第n個(gè)節(jié)點(diǎn)問(wèn)題握侧,例如LeetCode 19 Easy 刪除鏈表的倒數(shù)第N個(gè)節(jié)點(diǎn)
我們可以使用兩個(gè)指針而不是一個(gè)指針。第一個(gè)指針從列表的開(kāi)頭向前移動(dòng) n+1 步嘿期,而第二個(gè)指針將從列表的開(kāi)頭出發(fā)∑非妫現(xiàn)在,這兩個(gè)指針被 nn 個(gè)結(jié)點(diǎn)分開(kāi)备徐。我們通過(guò)同時(shí)移動(dòng)兩個(gè)指針向前來(lái)保持這個(gè)恒定的間隔孽查,直到第一個(gè)指針到達(dá)最后一個(gè)結(jié)點(diǎn)。此時(shí)第二個(gè)指針將指向從最后一個(gè)結(jié)點(diǎn)數(shù)起的第 nn 個(gè)結(jié)點(diǎn)坦喘。我們重新鏈接第二個(gè)指針?biāo)玫慕Y(jié)點(diǎn)的 next 指針指向該結(jié)點(diǎn)的下下個(gè)結(jié)點(diǎn)盲再。
??題目描述和官方解法如下:

LeetCode 19 刪除鏈表的倒數(shù)第N個(gè)節(jié)點(diǎn)

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode first = dummy;
    ListNode second = dummy;
    // Advances first pointer so that the gap between first and second is n nodes apart
    for (int i = 1; i <= n + 1; i++) {
        first = first.next;
    }
    // Move first to the end, maintaining the gap
    while (first != null) {
        first = first.next;
        second = second.next;
    }
    second.next = second.next.next;
    return dummy.next;
}

3.固定間距指針

??兩個(gè)指針從頭尾相向遍歷
??經(jīng)典用法就是用于解決二分查找問(wèn)題,或是n數(shù)之和等一系列問(wèn)題瓣铣。例如LeetCode 1答朋,LeetCode 15,LeetCode 18棠笑,這三道的難度分別是Easy运悲,Easy矾瑰,Medium,雖然難度是遞增的,但是其解法的中心思想一直沒(méi)變:對(duì)于有序數(shù)組竭宰,使用頭尾兩個(gè)指針雨膨,使用sum和target進(jìn)行比對(duì)留量,遍歷整個(gè)數(shù)組吼具。這里直接舉LeetCode 18 四數(shù)之和這個(gè)例子吧,其他太簡(jiǎn)單从橘。 四數(shù)之和
??題目描述和我個(gè)人的解法如下:

LeetCode 18 四數(shù)之和

 public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums == null || nums.length < 4) {
            return res;
        }

        int size = nums.length;
        Arrays.sort(nums);

        for (int i = 0; i < size - 3; i++) {

            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            int min = nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3];
            int max = nums[i] + nums[size - 3] + nums[size - 2] + nums[size - 1];
            if (min > target) {
                break;
            }
            if (max < target) {
                continue;
            }

            for (int j = i + 1; j < size - 2; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }

                int left = j + 1;
                int right = size - 1;

                int minSub = nums[i] + nums[j] + nums[left] + nums[left + 1];
                int maxSub = nums[i] + nums[j] + nums[right] + nums[right - 1];
                if (minSub > target) {
                    continue;
                }
                if (maxSub < target) {
                    continue;
                }

                while (left < right) {
                    int sum = nums[i] + nums[j] + nums[right] + nums[left];
                    if (sum == target) {
                        res.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[left], nums[right])));
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        left++;
                        right--;
                    } else if (sum < target) {
                        left++;
                    } else {
                        right--;
                    }
                }
            }
        }
        return res;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末念赶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子恰力,更是在濱河造成了極大的恐慌叉谜,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踩萎,死亡現(xiàn)場(chǎng)離奇詭異停局,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)董栽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)履怯,“玉大人,你說(shuō)我怎么就攤上這事裆泳。” “怎么了柠硕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵工禾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蝗柔,道長(zhǎng)闻葵,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任癣丧,我火速辦了婚禮槽畔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胁编。我一直安慰自己厢钧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布嬉橙。 她就那樣靜靜地躺著早直,像睡著了一般。 火紅的嫁衣襯著肌膚如雪市框。 梳的紋絲不亂的頭發(fā)上霞扬,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音枫振,去河邊找鬼喻圃。 笑死,一個(gè)胖子當(dāng)著我的面吹牛粪滤,可吹牛的內(nèi)容都是我干的斧拍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼杖小,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饮焦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起窍侧,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤县踢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后伟件,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體硼啤,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年斧账,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谴返。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煞肾。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嗓袱,靈堂內(nèi)的尸體忽然破棺而出籍救,到底是詐尸還是另有隱情,我是刑警寧澤渠抹,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布蝙昙,位于F島的核電站,受9級(jí)特大地震影響梧却,放射性物質(zhì)發(fā)生泄漏奇颠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一放航、第九天 我趴在偏房一處隱蔽的房頂上張望烈拒。 院中可真熱鬧,春花似錦广鳍、人聲如沸荆几。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)伴郁。三九已至,卻和暖如春蛋叼,著一層夾襖步出監(jiān)牢的瞬間焊傅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工狈涮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狐胎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓歌馍,卻偏偏與公主長(zhǎng)得像握巢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子松却,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355