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