搞定面试算法系列 | 分治算法三步走
戳藍(lán)字“CSDN云計(jì)算”關(guān)注我們哦!
作者 |?江子抑
轉(zhuǎn)自 |?編程拯救世界
?
主要思想
分治算法,即分而治之:把一個(gè)復(fù)雜問(wèn)題分成兩個(gè)或更多的相同或相似子問(wèn)題,直到最后子問(wèn)題可以簡(jiǎn)單地直接求解,最后將子問(wèn)題的解合并為原問(wèn)題的解。歸并排序就是一個(gè)典型的分治算法。
在這篇文章中我們將先介紹分治算法的「三步走套路」,然后通過(guò)經(jīng)典的歸并排序算法體驗(yàn)一番分治算法的核心,最后再通過(guò)真題演練一試身手!
三步走
和把大象塞進(jìn)冰箱一樣,分治算法只要遵循三個(gè)步驟即可:分解 -> 解決 -> 合并。
分解:分解原問(wèn)題為結(jié)構(gòu)相同的子問(wèn)題(即尋找子問(wèn)題)
解決:當(dāng)分解到容易求解的邊界后,進(jìn)行遞歸求解
合并:將子問(wèn)題的解合并成原問(wèn)題的解
分治算法三步走
這么一說(shuō)似乎還是有點(diǎn)抽象?那我們通過(guò)經(jīng)典的排序算法歸并排序來(lái)體驗(yàn)一下分治算法的核心思想。
歸并排序
思想
歸并排序的思想是:欲使序列有序,必先使其子序列有序。即先使得每個(gè)子序列有序,然后再將子序列合并成有序的列表。
因此,在歸并排序中的子問(wèn)題就是:使子序列有序。
三步走
既然已經(jīng)找到了問(wèn)題的子問(wèn)題,是時(shí)候套用我們上述的三步走方法了。歸并排序的「三步走」如下:
分解:將序列劃分為兩部分
解決:遞歸地分別對(duì)兩個(gè)子序列進(jìn)行歸并排序
合并:合并排序后的兩個(gè)子序列
舉例
來(lái)看一個(gè)具體的例子。
現(xiàn)在有一個(gè)待排序的序列:
10, 4, 6, 3, 8, 2, 5, 7
先對(duì)序列進(jìn)行分解,把該序列一分為二,直到無(wú)法拆分為止。整個(gè)拆分過(guò)程如下:
序列分解
然后對(duì)分解出的序列進(jìn)行兩兩排序與合并:
10, 4 排序合并后:4, 10
6, 3 排序合并后:3, 6
8, 2 排序合并后:2, 8
5, 7 排序合并后:5, 7
……
整個(gè)歸并排序完整過(guò)程如下:
上部分為「分解」,下部分為「解決」與「合并」
實(shí)現(xiàn)
def?merge_sort(lst):????#?從遞歸中返回長(zhǎng)度為1的序列????if?len(lst)?<=?1:????????return?lst??????????????middle?=?len(lst)?/?2????# 1.分解:通過(guò)不斷遞歸,將原始序列拆分成 n 個(gè)小序列????left?=?merge_sort(lst[:middle])?????????right?=?merge_sort(lst[middle:])????#?進(jìn)行排序與合并????return?merge(left,?right)def?merge(left,?right):????i,?j?=?0,?0????result?=?[]????# 2.解決:比較傳入的兩個(gè)子序列,對(duì)兩個(gè)子序列進(jìn)行排序????while?i?<?len(left)?and?j?<?len(right):??????????if?left[i]?<=?right[j]:????????????result.append(left[i])????????????i?+=?1????????else:????????????result.append(right[j])????????????j?+=?1????# 3.合并:將排好序的子序列合并????result.extend(left[i:])?????????????result.extend(right[j:])????return?result真題演練
為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級(jí)
LeetCode 241. 為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級(jí): https://leetcode-cn.com/problems/different-ways-to-add-parentheses/
題目描述
給定一個(gè)含有數(shù)字和運(yùn)算符的字符串,為表達(dá)式添加括號(hào),改變其運(yùn)算優(yōu)先級(jí)以求出不同的結(jié)果。你需要給出所有可能的組合的結(jié)果。有效的運(yùn)算符號(hào)包含 + , - 以及 *。
示例 1:
輸入:?"2-1-1"輸出:?[0,?2]解釋:?((2-1)-1)?=?0?(2-(1-1))?=?2示例 2:
輸入:?"2*3-4*5"輸出:?[-34,?-14,?-10,?-10,?10]解釋:?(2*(3-(4*5)))?=?-34?((2*3)-(4*5))?=?-14?((2*(3-4))*5)?=?-10?(2*((3-4)*5))?=?-10?(((2*3)-4)*5)?=?10思路
對(duì)于一個(gè)形如 x op y(op 為運(yùn)算符,x 和 y 為數(shù)) 的算式而言,它的結(jié)果組合取決于 x 和 y 的結(jié)果組合數(shù),而 x 和 y 又可以寫成形如 x op y 的算式。
因此,該問(wèn)題的子問(wèn)題就是 x op y 中的 x 和 y:以運(yùn)算符分隔的左右兩側(cè)算式解。
然后我們來(lái)進(jìn)行分治算法三步走:
分解:按運(yùn)算符分成左右兩部分,分別求解
解決:實(shí)現(xiàn)一個(gè)遞歸函數(shù),輸入算式,返回算式解
合并:根據(jù)運(yùn)算符合并左右兩部分的解,得出最終解
實(shí)現(xiàn)
class?Solution:????def?diffWaysToCompute(self,?input:?str)?->?List[int]:????????#?如果只有數(shù)字,直接返回????????if?input.isdigit():????????????return?[int(input)]????????res?=?[]????????for?i,?char?in?enumerate(input):????????????if?char?in?['+',?'-',?'*']:????????????????# 1.分解:遇到運(yùn)算符,計(jì)算左右兩側(cè)的結(jié)果集????????????????# 2.解決:diffWaysToCompute 遞歸函數(shù)求出子問(wèn)題的解????????????????left?=?self.diffWaysToCompute(input[:i])????????????????right?=?self.diffWaysToCompute(input[i+1:])????????????????# 3.合并:根據(jù)運(yùn)算符合并子問(wèn)題的解????????????????for?l?in?left:????????????????????for?r?in?right:????????????????????????if?char?==?'+':????????????????????????????res.append(l?+?r)????????????????????????elif?char?==?'-':????????????????????????????res.append(l?-?r)????????????????????????else:????????????????????????????res.append(l?*?r)????????return?res總結(jié)
分治算法的核心是尋找子問(wèn)題的解,解題步驟遵循「三步走」:
找到子問(wèn)題并分解
解決子問(wèn)題(遞歸)
合并子問(wèn)題的解
這里為大家準(zhǔn)備了兩道練手題,大家趕緊試試手吧:
LeetCode 932. 漂亮數(shù)組: https://leetcode-cn.com/problems/beautiful-array
LeetCode 105. 從前序與中序遍歷序列構(gòu)造二叉樹: https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
參考資料
OI Wiki: 遞歸 - 分治:https://oi-wiki.org/basic/divide-and-conquer/
福利
掃描添加小編微信,備注“姓名+公司職位”,加入【云計(jì)算學(xué)習(xí)交流群】,和志同道合的朋友們共同打卡學(xué)習(xí)!
推薦閱讀:
扛住100億次請(qǐng)求——如何做一個(gè)“有把握”的春晚紅包系統(tǒng)
Windows7一個(gè)月后停止服務(wù)支持;亞馬遜起訴特朗普;向量子計(jì)算商用發(fā)起挑戰(zhàn)!英特爾發(fā)布Horse Ridge低溫控制芯片……
扎心!12 月全國(guó)程序員工資統(tǒng)計(jì),半年工資僅漲 500 元!
數(shù)學(xué)學(xué)渣必備!拍照上傳,分步求解,微軟解題神器拯救你
TIOBE 12 月編程語(yǔ)言排行榜:爭(zhēng)奪年度編程語(yǔ)言,Java、C、Python、C# 即將開戰(zhàn)!
真香,朕在看了!
總結(jié)
以上是生活随笔為你收集整理的搞定面试算法系列 | 分治算法三步走的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Nutanix企业云助力嘉里大通提升核心
- 下一篇: 两大硬件设计被OCP官方接受,腾讯成国内