labuladong 的算法小抄_来自GitHub 68.8k star的硬核算法教程
很多朋友害怕算法,其實大可不必,算法題無非就那幾個套路,一旦掌握,就會覺得算法實在是太樸實無華且枯燥了!
本文選自硬核算法教程《labuladong的算法小抄》,帶你學習套路,把握各類算法問題的共性!
數據結構是工具,算法是通過合適的工具解決特定問題的方法。對于任何數據結構,其基本操作無非遍歷 + 訪問,再具體一點就是:增、刪、查、改。
那么該如何在力扣刷題呢?很多文章都會告訴你“按標簽刷”“堅持下去”等。不說這些不痛不癢的話,直接給具體的建議。
先刷二叉樹
先刷二叉樹
!!先刷二叉樹!!
這是我刷題一年的親身體會,下圖是 2019 年 10 月的提交截圖:
據我觀察,大部分人對與數據結構相關的算法文章不感興趣,而是更關心動態規劃、回溯、分治等技巧。這是不對的,這些常考算法技巧在《labuladong的算法小抄》中都會有所涉及,到時候你就會發現,它們看起來高大上,但本質上就是一個多叉樹遍歷的問題,配合算法框架,并沒有多難。
- 為什么要先刷二叉樹呢?
因為二叉樹是最容易培養框架思維的,而且大部分常考算法本質上都是樹的遍歷問題。
- 刷二叉樹時看到題目沒思路?
其實大家不是沒思路,只是沒有理解“框架”是什么。不要小看下面這幾行代碼,幾乎所有二叉樹的題目一套用這個框架就都出來了。
1void?traverse(TreeNode?root)?{2????//?前序遍歷3????traverse(root.left);4????//?中序遍歷5????traverse(root.right);6????//?后序遍歷7}比如隨便拿幾道題的解法代碼出來,這里不用管具體的代碼邏輯,只看看框架在其中是如何發揮作用的。
LeetCode 124 題 ,難度為 Hard,求二叉樹中最大路徑和,主要代碼如下:
1int?ans?=?INT_MIN; 2int?oneSideMax(TreeNode*?root)?{ 3????if?(root?==?nullptr)?return?0; 4 5????int?left?=?max(0,?oneSideMax(root->left)); 6????int?right?=?max(0,?oneSideMax(root->right)); 7 8????/****?后序遍歷?****/ 9????ans?=?max(ans,?left?+?right?+?root->val);10????return?max(left,?right)?+?root->val;11????/****************/12}你看,這不就是后序遍歷嘛。
那為什么是后序呢?題目要求最大路徑和,對于一個二叉樹節點,是不是先計算左子樹和右子樹的最大路徑和,然后加上自己的值,這樣就得出新的最大路徑和了?所以說這里就要使用后續遍歷框架。
LeetCode 105 題 ,難度為 Medi um,要求根據前序遍歷和中序遍歷的結果還原一棵二叉樹,這是很經典的問題,主要代碼如下:
1TreeNode?buildTree(int[]?preorder,?int?preStart,?int?preEnd,? 2????int[]?inorder,?int?inStart,?int?inEnd,?Map?inMap)?{ 3 4????if(preStart?>?preEnd?||?inStart?>?inEnd)?return?null; 5 6????/****?前序遍歷?****/ 7????TreeNode?root?=?new?TreeNode(preorder[preStart]); 8????int?inRoot?=?inMap.get(root.val); 9????int?numsLeft?=?inRoot?-?inStart;10????/****************/1112????root.left?=?buildTree(preorder,?preStart?+?1,?preStart?+?numsLeft,?13??????????????????????????inorder,?inStart,?inRoot?-?1,?inMap);14????root.right?=?buildTree(preorder,?preStart?+?numsLeft?+?1,?preEnd,?15??????????????????????????inorder,?inRoot?+?1,?inEnd,?inMap);16????return?root;17}不要看這個函數的參數很多,它們只是為了控制數組索引而已,本質上該算法就是一個前序遍歷算法。
LeetCode 99 題 ,難度為 Hard,要求恢復一棵 BST(完全二叉樹),主要代碼如下:
1void?traverse(TreeNode*?node)?{ 2????if?(!node)?return; 3 4????traverse(node->left); 5 6????/****中序遍歷?****/ 7????if?(node->val?val)?{ 8????????s?=?(s?==?NULL)???prev?:?s; 9????????t?=?node;10????}11????prev?=?node;12????/****************/1314????traverse(node->right);15}這不就是中序遍歷嘛,對于一棵 BST,中序遍歷意味著什么,應該不需要解釋了吧。
你看,Hard 難度的題目不過如此,而且還這么有規律可循,只要把框架寫出來,然后往相應的位置加內容就行了,這不就是思路嘛!
對于一個理解二叉樹的人來說,刷一道二叉樹的題目花不了多長時間。那么如果你對刷題無從下手或者有畏懼心理,不妨從二叉樹下手,前 10 道也許有點難受;結合框架再做 20 道題,也許你就有點自己的理解了;刷完整個專題,再去做什么回溯、動態規化、分治專題,你就會發現只要涉及遞歸的問題,基本上都是樹的問題。
▽▽▽
再舉些例子吧。
在《labuladong的算法小抄》“動態規劃解題套路框架”章節中,會講到湊零錢問題,暴力解法就是遍歷一棵 N 叉樹:
1def?coinChange(coins:?List[int],?amount:?int): 2 3????def?dp(n): 4????????if?n?==?0:?return?0 5????????if?n?這么多代碼看不懂怎么辦?直接提取框架,這樣就能看出核心思路了,這就是剛才說到的遍歷 N 叉樹的框架:
1def?dp(n):2????for?coin?in?coins:3????????dp(n?-?coin)其實很多動態規劃問題就是在遍歷一棵樹,你如果對樹的遍歷操作爛熟于心,那么起碼知道怎么把思路轉化成代碼,也知道如何提取別人解法的核心思路。
再看看回溯算法,在《labuladong的算法小抄》“回溯算法解題套路框架”中會直接告訴你,回溯算法就是一個 N 叉樹的前序 + 后序遍歷問題,沒有例外。比如,排列組合問題、經典的回溯問題,主要代碼如下:
1void?backtrack(int[]?nums,?LinkedList?track)?{ 2????if?(track.size()?==?nums.length)?{ 3????????res.add(new?LinkedList(track)); 4????????return; 5????} 6 7????for?(int?i?=?0;?i??track)?{18????for?(int?i?=?0;?i?N 叉樹的遍歷框架,找出來了吧。你說,樹這種結構重不重要?
綜上所述,對于畏懼算法或者刷題很多但依然感覺不得要領的朋友來說,可以先刷樹的相關題目,試著從框架看問題,而不要糾結于細節。
所謂糾結細節,就比如糾結 i 到底應該加到 n 還是加到 n - 1 ,這個數組的大小到底應該開成 n 還是 n + 1 ?
從框架看問題,就是像我們這樣基于框架進行抽取和擴展,既可以在看別人解法時快速理解核心邏輯,也有助于我們找到自己寫解法時的思路方向。
當然,如果細節出錯,你將得不到正確的答案,但是只要有框架,再錯也錯不到哪去,因為你的方向是對的。但是,你要是心中沒有框架,那么根本無法解題,給你答案,也不能意識到這就是樹的遍歷問題。
框架思維是很重要的,有時候按照流程寫出解法,說實話我自己都不知道為啥是對的,反正它就是對了……
這就是框架的力量,能夠保證你在思路不那么清晰的時候,依然寫出正確的程序。
—— ——
最后我們總結一下,刷算法題建議從“樹”分類開始刷,結合框架思維,把幾十道題刷完,對于樹結構的理解應該就到位了。這時候去看回溯、動態規劃、分治等算法專題,對思路的理解可能會更加深刻一些。
在思考問題的過程中,少糾結細節,不要熱衷于炫技;希望讀者多從框架看問題,多學習套路,把握各類算法問題的共性,《labuladong的算法小抄》將會為你提供這方面的幫助。
圖書推薦
▊《labuladong的算法小抄》
付東來(@labuladong) 著
- GitHub 68.8k star的硬核算法教程
- labuladong帶你挑戰力扣算法題
- 挑戰BAT等大廠Offer
本書專攻算法刷題,訓練算法思維,應對算法筆試。注重用套路和框架思維解決問題,以不變應萬變。
總結
以上是生活随笔為你收集整理的labuladong 的算法小抄_来自GitHub 68.8k star的硬核算法教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zabbixdocker里的mysql_
- 下一篇: opc服务器不显示目录,本地OPC服务器