双指针法总结之倚天屠龙
引言
假期在看這塊知識(shí)時(shí),突然想到雙指針中的”快慢指針“就像是倚天劍,一前一后單向執(zhí)行(就像倚天劍被滅絕師太和周芷若依次拿到那樣),就是為了測試鏈表環(huán)的問題(為了測試武當(dāng)七子連環(huán)陣的環(huán)是否有問題);而”左右指針“就像屠龍刀,在使用時(shí)有一些前提:金毛獅王謝遜拿著時(shí)(數(shù)組有序啥的),然后用來進(jìn)行二分搜索,加上遞歸解決Nsum問題,威猛無比
類比學(xué)習(xí)法而已,唯博君一笑耳!
雙指針技巧分類:
雙指針技巧分為兩類:
- 一類是“快慢指針(倚天劍)”,主要解決鏈表中的問題,比如典型的判定鏈表中是否包含環(huán);
- 一類是“左右指針(屠龍刀)”,主要解決數(shù)組/字符串中的問題,比如二分搜索。
一、快慢指針法-倚天劍
快慢指針一般會(huì)初始化指向鏈表的頭結(jié)點(diǎn)head,前進(jìn)時(shí)快指針fast在前,慢指針slow在后,巧妙解決一些鏈表中的問題。
判斷鏈表中是否有環(huán)
經(jīng)典解法雙指針,一個(gè)跑得快,一個(gè)跑得慢。如果不含有環(huán),跑的快的那個(gè)指針最終會(huì)遇到null,說明鏈表不含環(huán);如果含有環(huán),快指針最后會(huì)超慢指針1圈,和慢指針相遇,說明鏈表含有環(huán)。
已知鏈表中含有環(huán),返回這個(gè)環(huán)的起始位置
解法:當(dāng)快慢指針相遇時(shí),讓其中任何一個(gè)指針指向頭結(jié)點(diǎn),然后兩個(gè)指針以相同速度前進(jìn),再次相遇時(shí)所在的節(jié)點(diǎn)位置就是環(huán)開始的位置。
原因:假設(shè)第一次相遇時(shí),假設(shè)慢指針slow走了k步,那么快指針走了2k步,得到快指針多了了一圈為k步。設(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)。
尋找無環(huán)單鏈表的重點(diǎn)
笨方法:先指針遍歷一遍,記錄中節(jié)點(diǎn)個(gè)數(shù)為n,然后從頭再來走n/2步
優(yōu)雅解法:快指針一次走兩步,慢指針一次走一步,當(dāng)快指針到鏈表盡頭時(shí),慢指針就處于鏈表的中間位置。
應(yīng)用:尋找鏈表中點(diǎn)的一個(gè)重要作用就是對(duì)鏈表進(jìn)行歸并排序。對(duì)兩部分鏈表分別排序,然后合并為有序數(shù)組。
尋找單鏈表的倒數(shù)第k個(gè)元素
還是快慢指針,讓快指針先走k步,然后快慢指針同時(shí)前進(jìn)??熘羔樀芥湵肀M頭時(shí),慢指針?biāo)谖恢镁褪堑箶?shù)第k個(gè)鏈表節(jié)點(diǎn)
二、左右指針法-屠龍刀
基本用法:一般初始化為left=0,right=len(num)-1
二分搜索
左右指針在數(shù)組兩端初始化,左指針往右走,右指針往做走,直至找到目標(biāo)值
兩數(shù)之和
數(shù)組有序時(shí),就應(yīng)該想到雙指針技巧。類似二分搜索,通過sum大小調(diào)節(jié)left和right的移動(dòng),直至找到目標(biāo)對(duì)
翻轉(zhuǎn)數(shù)組
左右指針在數(shù)組兩端初始化,相向而行,同時(shí)交互對(duì)應(yīng)的元素
滑動(dòng)窗口算法
雙指針技巧的最高境界??炻羔樤跀?shù)組/字符串上的應(yīng)用。如果掌握了該算法,既可以解決一大類字符串匹配問題
三、左右指針法高級(jí)用法之-二分搜索算法(屠龍刀威力之一)
場景:給定一個(gè)數(shù)尋找左側(cè)邊界、尋找右側(cè)邊界
技巧:
? 1)不要出現(xiàn)else,而是把所有情況用else if寫清楚,這樣可以清晰展現(xiàn)所有細(xì)節(jié);
? 2)計(jì)算mid時(shí)要防止溢出,推薦使用left + (right-left)/2,而不是(left + right)/2。
尋找一個(gè)數(shù)(基本二分搜索)
數(shù)組排序?yàn)橛行?#xff0c;左右指針根據(jù)大小判斷左右指針依次相向而行,找到目標(biāo)值
差異梳理:因?yàn)槲覀兂跏蓟痳ight = num.length-1,決定了我們搜索區(qū)間是[left,right]
所以決定了while(left <= right),同時(shí)也決定了left=mid+1和right=mid-1
因此我們只需要找到一個(gè)target的索引即可,所以當(dāng)nums[mid] == target時(shí)可以立即返回
尋找左側(cè)邊界的二分搜索
[1,2,2,2,3]返回下標(biāo)1
差異梳理:因?yàn)槲覀兂跏蓟痳ight = num.length,決定了我們搜索區(qū)間是[left,right)
所以決定了while(left < right),同時(shí)也決定了left=mid+1和right=mid
因?yàn)槲覀冃枰业絫arget的最左側(cè)索引即可,所以當(dāng)nums[mid] == target時(shí)不要立即返回,而要收縮右側(cè)邊界以鎖定左側(cè)邊界
尋找右側(cè)邊界的二分搜索
[1,2,2,2,3]返回下標(biāo)3
差異梳理:因?yàn)槲覀兂跏蓟痳ight = num.length,決定了我們搜索區(qū)間是[left,right)
所以決定了while(left < right),同時(shí)也決定了left=mid+1和right=mid
因?yàn)槲覀冃枰业絫arget的最右側(cè)索引即可,所以當(dāng)nums[mid] == target時(shí)不要立即返回,而要收縮左側(cè)邊界以鎖定右側(cè)邊界。 又因?yàn)槭湛s左側(cè)邊界時(shí)必須left = mid+1,所以無論是left還是right,必須減1
邏輯統(tǒng)一:
對(duì)于尋找左右邊界的二分搜索,常見的方式是使用左閉右開的"搜索區(qū)間"。我們還根據(jù)邏輯將"搜索區(qū)間"全部統(tǒng)一成兩端都閉,便于記憶,好記,只要稍改nums[mid] == target條件處的代碼和函數(shù)返回的代碼邏輯即可,推薦拿小本子記下內(nèi)容,作為二分搜索模板。
四、左右指針法高級(jí)用法之-Nsum問題(屠龍刀威力之二)
2Sum的核心解法
笨方法:二重循環(huán)窮舉,時(shí)間復(fù)雜度O(N2),空間復(fù)雜度為O(1)
優(yōu)雅方法:用空間換時(shí)間,通過哈希表記錄元素值到索引的映射,減少時(shí)間復(fù)雜度;
2Sum問題就是想教我們?nèi)绾问褂霉1斫鉀Q問題
2Sum問題不重復(fù)結(jié)果對(duì)
基本思路是排序加雙指針,但是會(huì)出現(xiàn)結(jié)果重復(fù)。出問題的地方在于sum == target條件的if分支,當(dāng)給res加入結(jié)果后,lo和hi在改變1的同時(shí),還應(yīng)該跳過所有重復(fù)元素。
3Sum問題
笨方法:窮舉
優(yōu)雅方法:使用遍歷第一個(gè)數(shù)然后調(diào)用2Sum,關(guān)鍵點(diǎn)在于不能讓第一個(gè)數(shù)重復(fù),至于后面的2個(gè)數(shù),復(fù)用的2Sum函數(shù)會(huì)保證他們不重復(fù)
時(shí)間復(fù)雜度O(N2)
4Sum問題
相同套路:窮舉第一個(gè)數(shù)組,然后使用3Sum解決剩下3個(gè)數(shù),然后組合出和為target的四元組。
Num 問題
首先對(duì)nums數(shù)組排序,然后n == 2時(shí)是2Sum的雙指針解法,n > 2時(shí)就是窮舉第一個(gè)數(shù)字,然后遞歸調(diào)用計(jì)算(n-1)Sum,組裝答案
總結(jié)
以上是生活随笔為你收集整理的双指针法总结之倚天屠龙的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle utl file putf
- 下一篇: [物联网篇 ] 15 -博通AP6255