<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Dynamic Programming on 跟著 Desolve 學程式</title><link>https://desolve.pages.dev/tags/dynamic-programming/</link><description>Recent content in Dynamic Programming on 跟著 Desolve 學程式</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><lastBuildDate>Mon, 20 Jul 2020 00:00:00 +0800</lastBuildDate><atom:link href="https://desolve.pages.dev/tags/dynamic-programming/index.xml" rel="self" type="application/rss+xml"/><item><title>從LeetCode學演算法 - 100 Dynamic Programming (14)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-100-dynamic-programming-14/</link><pubDate>Mon, 20 Jul 2020 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-100-dynamic-programming-14/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 100 Dynamic Programming (14)" /&gt;&lt;p&gt;&lt;strong&gt;1510. Stone Game IV (Hard)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="寫在前面"&gt;寫在前面
&lt;/h2&gt;&lt;p&gt;扣掉第0篇外，這篇是100篇啦！！！**從開始寫以來，一路到現在其實也不容易，&lt;br&gt;
雖然頻率因為工作和開課的關係降低很多，&lt;br&gt;
但希望大家仍然從文章中能有所收穫。&lt;/p&gt;
&lt;p&gt;100篇好像應該要來個感恩回饋(?)&lt;br&gt;
那這樣好了，如果有任何問題，&lt;br&gt;
歡迎在本篇底下發問(Python Taiwan也可以)，&lt;br&gt;
同時請在&lt;strong&gt;Python Taiwan的連結本篇文的文章&lt;/strong&gt; 底下，&lt;br&gt;
&lt;strong&gt;公開分享到你的臉書、按讚該篇文章、並留言告訴我說，&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;「你最喜歡這一整個系列的哪一篇？為什麼？」或&lt;br&gt;
「除了從LeetCode學演算法系列以外，&lt;br&gt;
你還想要看到關於什麼方向的文章？」&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;超過20則留言的話&lt;/strong&gt; (有完成以上步驟的才算)，我們就抽一組&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」&lt;br&gt;
課程的免費兌換券進行贈送！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;截止時間為7/31 23:59:59，這之後的留言問題我有看到還是會回答，&lt;br&gt;
但就不會納入抽獎資格歐！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果留言人數不足的話，&lt;br&gt;
那我可能就以一篇文章的形式來回應大家的問題，&lt;br&gt;
就不會進行抽獎囉XD&lt;/p&gt;
&lt;p&gt;感謝大家的支持與肯定，期待我們都能從這當中(我寫文章，你們讀文章XD)&lt;br&gt;
不斷成長，進而提升自己的程式能力！&lt;/p&gt;
&lt;p&gt;容筆者工商一下，&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」&lt;/strong&gt; 開放預購啦！&lt;br&gt;
這次選了40道難度加深的LeetCode題目，&lt;br&gt;
同樣也會細部解說對應的技巧及須要掌握的演算法！&lt;br&gt;
同時這次購買進階篇的話，&lt;br&gt;
額外還加贈**「從Leetcode學演算法｜面試篇」** ！面試篇已經全數上傳啦~&lt;br&gt;
當中包含了&lt;strong&gt;面試準備須知分享&lt;/strong&gt; ，&lt;strong&gt;及訪談國內外不同經驗的工程師&lt;/strong&gt; ，&lt;br&gt;
讓你不論是&lt;strong&gt;想走前端/後端/一般軟工&lt;/strong&gt; 或者是&lt;strong&gt;想找國外的工作&lt;/strong&gt; ，&lt;br&gt;
是&lt;strong&gt;初學想轉職&lt;/strong&gt; 還是&lt;strong&gt;正在工作&lt;/strong&gt; ，都能夠從中得到收穫呦！&lt;br&gt;
有興趣的朋友可以使用下面的早鳥優惠～&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」&lt;/strong&gt; ：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/advleetcode" target="_blank" rel="noopener"
&gt;https://bit.ly/advleetcode&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：&lt;/strong&gt;&lt;br&gt;
&lt;a class="link" href="https://bit.ly/allleetcode" target="_blank" rel="noopener"
&gt;https://bit.ly/allleetcode&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Alice and Bob take turns playing a game, with Alice starting first.&lt;/p&gt;
&lt;p&gt;Initially, there are &lt;code&gt;n&lt;/code&gt; stones in a pile. On each player&amp;rsquo;s turn, that player makes a &lt;em&gt;move&lt;/em&gt; consisting of removing &lt;strong&gt;any&lt;/strong&gt; non-zero ** square number** of stones in the pile.&lt;/p&gt;
&lt;p&gt;Also, if a player cannot make a move, he/she loses the game.&lt;/p&gt;
&lt;p&gt;Given a positive integer &lt;code&gt;n&lt;/code&gt;. Return &lt;code&gt;True&lt;/code&gt; if and only if Alice wins the game otherwise return &lt;code&gt;False&lt;/code&gt;, assuming both players play optimally.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: n = 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: Alice can remove 1 stone winning the game because Bob doesn&amp;#39;t have any moves.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: n = 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: false
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: Alice can only remove 1 stone, after that Bob removes the last one winning the game (2 -&amp;gt; 1 -&amp;gt; 0).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-3"&gt;Example 3
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: n = 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: n is already a perfect square, Alice can win with one move, removing 4 stones (4 -&amp;gt; 0).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-4"&gt;Example 4
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: n = 7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: false
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: Alice can&amp;#39;t win the game if Bob plays optimally.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If Alice starts removing 4 stones, Bob will remove 1 stone then Alice should remove only 1 stone and finally Bob removes the last one (7 -&amp;gt; 3 -&amp;gt; 2 -&amp;gt; 1 -&amp;gt; 0).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If Alice starts removing 1 stone, Bob will remove 4 stones then Alice only can remove 1 stone and finally Bob removes the last one (7 -&amp;gt; 6 -&amp;gt; 2 -&amp;gt; 1 -&amp;gt; 0).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-5"&gt;Example 5
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: n = 17
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: false
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: Alice can&amp;#39;t win the game if Bob plays optimally.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;Alice和Bob玩不膩的撿石頭遊戲又來啦！&lt;br&gt;
這次一樣是Alice先開始，一堆石頭裡面有n個石頭，每次玩家行動時，&lt;br&gt;
可以選擇拿走某個非0的平方數的石頭數量，稱為一次行動。&lt;br&gt;
(也就是1的平方、2的平方、3的平方&amp;hellip;等)&lt;br&gt;
當有人無法作任何行動的時候(也就是沒有任何石頭能拿)，就輸惹QQ&lt;br&gt;
給定正整數n代表石頭的個數，如果Alice確定可以贏遊戲的話，&lt;br&gt;
就回傳True，反之則回傳False。(假定雙方都採最佳的策略來進行)&lt;/p&gt;
&lt;p&gt;由於每次要拿非0的平方數，所以不能pass，&lt;br&gt;
這就保證了遊戲一定會結束，&lt;br&gt;
因為最後一定會拿到空掉，下一個人會輸掉。&lt;/p&gt;
&lt;p&gt;我們來考慮一下前面幾個狀況，來觀察一下有沒有什麼規律：&lt;br&gt;
n = 0: False -&amp;gt; 顯然就是輸了嘛XD&lt;br&gt;
n = 1: True -&amp;gt; Alice拿走1顆(1²)，由於拿光了，所以Alice贏。&lt;br&gt;
n = 2: False -&amp;gt; Alice只能選擇拿1顆，Bob再拿1顆就沒了，Alice輸掉。&lt;br&gt;
n = 3: True -&amp;gt; 只有1, 1, 1的選擇，所以Alice贏&lt;br&gt;
n = 4: True -&amp;gt; Alice拿走4顆(2²)，直接獲勝&lt;/p&gt;
&lt;p&gt;看起來好像沒有很明顯對吧？&lt;br&gt;
但這邊可以從題目中思考到一個關鍵，由於雙方都是以最好的策略，&lt;br&gt;
也就是&lt;strong&gt;Bob不會該贏卻沒贏&lt;/strong&gt; ，所以以下兩點是我們可以確定的：&lt;br&gt;
&lt;strong&gt;1. 當n直接是完全平方數時，Alice可以贏&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;2. 當n=x會讓Bob贏(Alice輸)的時候，n在以下狀況時Alice會贏：&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;x+1, x+4, x+9, x+16…&lt;/strong&gt;&lt;br&gt;
因為這時候Alice只要拿掉對應的石頭，讓Bob碰到x的狀況，&lt;br&gt;
這時候就反而變成Bob會輸了！&lt;br&gt;
&lt;strong&gt;(Alice先拿會輸的狀況，換成Bob先拿也會輸)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由於這個狀況只限定於我們發現前一個False，&lt;br&gt;
所以我們必須從已經確定的值去推論，&lt;br&gt;
假設今天我們想要知道&lt;strong&gt;n = i的值是否為True&lt;/strong&gt; ，&lt;br&gt;
我們需要先知道&lt;strong&gt;n=0~i-1的值&lt;/strong&gt; ，&lt;br&gt;
接著檢查是否有任何一個&lt;strong&gt;n=i-j²&lt;/strong&gt; 的結果是&lt;strong&gt;False&lt;/strong&gt; (留意&lt;strong&gt;j²要小於等於i&lt;/strong&gt; )&lt;br&gt;
只要有一個符合，那n=i的值就是True，&lt;br&gt;
如果全部檢查完都沒有的話，n=i的值即為False。&lt;br&gt;
由於n=i的值會跟前面n=i-j²的結果有關係，&lt;br&gt;
這是一個很明顯的動態規劃的題目。&lt;/p&gt;
&lt;p&gt;因此，我們的程式流程應該像這樣：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先初始化dp的陣列&lt;/strong&gt; ，其長度為n+1，並先全初始化成False。&lt;/li&gt;
&lt;li&gt;執行一個迴圈，讓&lt;strong&gt;i從1~n (0已經是False了直接跳過)&lt;/strong&gt; ：&lt;br&gt;
2-1. 在裡面再開一個迴圈，讓j從1遞增到&lt;strong&gt;最大j² == i&lt;/strong&gt; 為止&lt;br&gt;
2-2. &lt;strong&gt;若dp[i - j²]為False，將dp[i]設為True&lt;/strong&gt; 並且&lt;strong&gt;break&lt;/strong&gt; 離開這層迴圈&lt;br&gt;
(已經確定True就不用往下找了)&lt;/li&gt;
&lt;li&gt;整個雙層迴圈完成後，我們應該處理完成了整個dp的陣列，&lt;br&gt;
只要&lt;strong&gt;回傳dp[n]&lt;/strong&gt; 即可。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;依此，寫成程式碼如下：&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;Java的部分，由於boolean陣列初始化的預設值就是False，&lt;br&gt;
就不用額外作初始化了。(C++的話還是記得要初始化啊！)&lt;br&gt;
要使用ArrayList也可以，但長度確定固定的話，其實直接開陣列比較快。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/acd48dc4a54ef456891392ce66320d20.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分，我們當然也可以一路append，&lt;br&gt;
但直接初始化串列比較乾脆，內層的迴圈則使用while來檢查條件，&lt;br&gt;
不要忘記每次將j遞增。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/1cd994d7e2b4551ab9da30c503583717.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(&lt;strong&gt;O(n^(3/2))/O(n)&lt;/strong&gt; 外層迴圈要跑n次，內層最大是根號n；&lt;br&gt;
空間上使用dp的陣列/串列外，沒有額外的需求了)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://medium.com/@desolution/%E5%BE%9Eleetcode%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-61-dynamic-programming-9-784b21b36c47?sk=5ef10c13e32c0b2dcf6e25420b7f7141" target="_blank" rel="noopener"
&gt;1140. Stone Game II (Medium)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;別忘了，要抽獎的讀者記得去Python Taiwan按讚留言分享歐！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;另外，&lt;strong&gt;「從Leetcode學演算法｜基礎篇」&lt;/strong&gt; 已經回原價囉，&lt;br&gt;
先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，&lt;br&gt;
雖然&lt;strong&gt;整捆一起買總體比較划算&lt;/strong&gt; (差290而已就有整組了阿XD)，&lt;br&gt;
如果你還是想先試試基礎課的話，&lt;br&gt;
&lt;strong&gt;300元折抵的連結&lt;/strong&gt; 在這邊：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/1desolve" target="_blank" rel="noopener"
&gt;https://bit.ly/1desolve&lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 97 Dynamic Programming (13)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-97-dynamic-programming-13/</link><pubDate>Wed, 17 Jun 2020 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-97-dynamic-programming-13/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 97 Dynamic Programming (13)" /&gt;&lt;p&gt;&lt;strong&gt;0368. Largest Divisible Subset (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="寫在前面"&gt;寫在前面
&lt;/h2&gt;&lt;p&gt;容筆者工商一下，&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」&lt;/strong&gt; 開放預購啦！&lt;br&gt;
這次選了40道難度加深的LeetCode題目，&lt;br&gt;
同樣也會細部解說對應的技巧及須要掌握的演算法！&lt;br&gt;
同時這次購買進階篇的話，&lt;br&gt;
額外還加贈**「從Leetcode學演算法｜面試篇」** ！&lt;br&gt;
當中包含了&lt;strong&gt;面試準備須知分享&lt;/strong&gt; ，&lt;strong&gt;及訪談國內外不同經驗的工程師&lt;/strong&gt; ，&lt;br&gt;
讓你不論是&lt;strong&gt;想走前端/後端/一般軟工&lt;/strong&gt; 或者是&lt;strong&gt;想找國外的工作&lt;/strong&gt; ，&lt;br&gt;
是&lt;strong&gt;初學想轉職&lt;/strong&gt; 還是&lt;strong&gt;正在工作&lt;/strong&gt; ，都能夠從中得到收穫呦！&lt;br&gt;
有興趣的朋友可以使用下面的早鳥優惠～&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」&lt;/strong&gt; ：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/2desolve" target="_blank" rel="noopener"
&gt;https://bit.ly/2desolve&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：&lt;/strong&gt;&lt;br&gt;
&lt;a class="link" href="https://bit.ly/adesolve" target="_blank" rel="noopener"
&gt;https://bit.ly/adesolve&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given a set of &lt;strong&gt;distinct&lt;/strong&gt; positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies:&lt;/p&gt;
&lt;p&gt;Si % Sj = 0 or Sj % Si = 0.&lt;/p&gt;
&lt;p&gt;If there are multiple solutions, return any subset is fine.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [1,2,3]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: [1,2] (of course, [1,3] will also be ok)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [1,2,4,8]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: [1,2,4,8]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;給定一個內含不同正整數的集合，找出最大的子集合，使得當中任取一對元素(Si, Sj)出來均能符合Si整除Sj或Sj整除Si。&lt;br&gt;
如果有多個不同的解，回傳當中任何一個都可以。&lt;/p&gt;
&lt;p&gt;首先我們可以先想到，在這個題目當中顯然nums是沒有被排序的，&lt;br&gt;
如果以最笨的辦法來說的話，一個集合會擁有2^N個子集合&lt;br&gt;
(因為每個元素都可以選擇要在這個子集合或不在這個子集合內)，&lt;br&gt;
而每個組合當中如果又要兩兩檢查的話，又要各自花上n(n-1)/2的時間。&lt;br&gt;
(n為該子集合的元素數量)&lt;br&gt;
顯然直接考慮是非常不符合的，所以只好嘗試先排序過後，&lt;br&gt;
看看能得到什麼可以用的特性。&lt;/p&gt;
&lt;p&gt;那在排序過後，我們會想到一個點是，如果我們由小到大看的話，&lt;br&gt;
&lt;strong&gt;假設前面選取了a跟b，那下一個選取的數c只需要確定能被b整除即可。&lt;/strong&gt;&lt;br&gt;
為什麼？因為按順序由小到大排，所以當我們選b的時候，&lt;br&gt;
一定是要b能被a整除才行，於是後面接續的選擇，&lt;br&gt;
只要確保能被最後一個數整除，就會符合能被前面的其他數整除了！&lt;/p&gt;
&lt;p&gt;接著下來，假設我們觀察一下數列的規律：&lt;br&gt;
假設有一個數列是1, 2, 3, 4, 6, 8, 12, 18，&lt;br&gt;
我們可以稍微列出幾串能成立Divisible Subset的內容&lt;br&gt;
(先不考慮有沒有最大個數)：&lt;br&gt;
&lt;strong&gt;1, 2, 4&lt;/strong&gt; , 8&lt;br&gt;
&lt;strong&gt;1, 3,&lt;/strong&gt; 6, 12&lt;br&gt;
1, 3, 6, &lt;strong&gt;18&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1, 2&lt;/strong&gt; , 6, 12&lt;br&gt;
&lt;strong&gt;1, 2,&lt;/strong&gt; 6, 18&lt;/p&gt;
&lt;p&gt;有沒有發現，當中間選的不一樣，後面能接的數字也就不一樣，&lt;br&gt;
&lt;strong&gt;從最大的數字往回推的時候，上一個index就有可能因而改變。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由於我們在考慮的是如何去找前面已經選取的子集合，&lt;br&gt;
和下面要選取的數的關係，所以這基本上就是動態規劃的題目跑不了XD!&lt;/p&gt;
&lt;p&gt;那麼，該怎麼樣定這中間的關係呢？&lt;br&gt;
首先選取我們的dp，這個值要能夠拿來比較哪個子集合是擁有最多元素的，&lt;br&gt;
那我們不妨這麼定義：&lt;br&gt;
&lt;strong&gt;dp[i]就是從已經排序好的nums中，從index 0~i的數字中，&lt;br&gt;
選取出來最大可整除的子集合其元素的個數，且這個子集合當中必須包含nums[i]。&lt;strong&gt;為什麼要定義必須包含nums[i]呢？因為不管怎麼樣，&lt;br&gt;
最起碼可以選取index i，這樣子我們就可以將所有&lt;/strong&gt;dp[i]先初始化為1&lt;/strong&gt; ，&lt;br&gt;
因為這是它的保底。&lt;/p&gt;
&lt;p&gt;接下來，我們要怎麼去紀錄當確立一個子集合的時候，&lt;br&gt;
整個子集合的長相呢？&lt;br&gt;
可以利用每個比較大的數只需要看前面一個數是否能將其整除的特性，&lt;br&gt;
定義一組陣列或串列，當中存放符合前面dp定義的時候，&lt;br&gt;
nums[i]的&lt;strong&gt;對應到前面一個數的index在哪裡&lt;/strong&gt; ，&lt;br&gt;
將其稱呼為lidx(last index)。我們在找到最大的解的時候，&lt;br&gt;
後續可以利用lidx來列出整個解。因此，&lt;strong&gt;將lidx全部初始化為-1&lt;/strong&gt; ，&lt;br&gt;
當我們最後迴圈找尋遇到-1的時候，就表示整個解都被我們列出來了。&lt;/p&gt;
&lt;p&gt;那接下來就簡單了，定義一個全局最大解所在的索引值max_idx，&lt;br&gt;
以及最大解的元素總數max_dp，分別初始化成0跟1。&lt;br&gt;
接下來我們需要一個雙層的迴圈，第一層迴圈是&lt;strong&gt;i從0開始到nums尾端&lt;/strong&gt; ，&lt;br&gt;
以nums[i]做為當下這個子集合的最大值。&lt;br&gt;
而第二層迴圈則是&lt;strong&gt;j從i-1開始到0&lt;/strong&gt; ，&lt;br&gt;
目的是要一路往回找nums[i]是否整除nums[j]。&lt;br&gt;
如果整除的話，代表有一個子集合的排列方式是：&lt;br&gt;
&amp;hellip;&amp;hellip; , nums[j], nums[i]&lt;br&gt;
這個子集合是不是對i來說是最好的狀況呢？&lt;br&gt;
那就要看&lt;strong&gt;dp[j]+1是不是比dp[i]還要大&lt;/strong&gt; ，&lt;br&gt;
如果比較大，才表示i的排列要換成走j這條線對吧XD？&lt;br&gt;
所以&lt;strong&gt;比較大&lt;/strong&gt; 的話，我們就應該要&lt;strong&gt;把dp[i]的值改成dp[j] + 1&lt;/strong&gt; ，&lt;br&gt;
並且&lt;strong&gt;lidx[i]要改成j&lt;/strong&gt; (因為改成走nums[j]這條路了)。&lt;br&gt;
每次將j走完以後，dp[i]有可能被改變，&lt;br&gt;
自然全局最大的解也有可能被改變，所以我們要檢查看看，&lt;br&gt;
如果需要更動，就進行更動。&lt;/p&gt;
&lt;p&gt;如此完成了雙層迴圈後，&lt;br&gt;
最後就&lt;strong&gt;從max_idx開始以一個單層迴圈將解列出來&lt;/strong&gt; ，&lt;br&gt;
記得迴圈的&lt;strong&gt;結束條件是index碰到-1&lt;/strong&gt; (代表已經到頭了)。&lt;/p&gt;
&lt;p&gt;依此，寫成程式碼如下：&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;Java的部分，可以用Arrays.fill來進行填充初始值的動作，&lt;br&gt;
其他則是使用ArrayList來將res一個一個加入(要用LinkedList也可以)。&lt;br&gt;
最後一個for迴圈的部分，如果使用者不想留max_idx，&lt;br&gt;
也可以直接使用while來操作，&lt;br&gt;
每次的下一步則是&lt;strong&gt;max_idx = lidx[max_idx]&lt;/strong&gt; 。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/fdd2bb1e1469cff9ee02e721b9a71c09.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分則是用[x] * n的方式來初始化，其他的部分跟Java並無不同。&lt;br&gt;
請留意將串列原地排要用&lt;strong&gt;nums.sort()&lt;/strong&gt; ，&lt;br&gt;
如果用&lt;strong&gt;sorted(nums)&lt;/strong&gt; 的話則是會&lt;strong&gt;回傳一個新的排序好的串列&lt;/strong&gt; 。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/d6eb9b87f4c27cdd59a3e7a129c62fba.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(N²)/O(N)，因為時間用到雙層迴圈，每層都是O(N)要相乘，&lt;br&gt;
而O(N²)會大於排序用的O(NlogN)，所以就取O(N²)；&lt;br&gt;
空間上則用到dp跟lidx，均為O(N))&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;
&lt;p&gt;另外，&lt;strong&gt;「從Leetcode學演算法｜基礎篇」&lt;/strong&gt; 已經回原價囉，&lt;br&gt;
先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，&lt;br&gt;
雖然&lt;strong&gt;整捆一起買總體比較划算&lt;/strong&gt; (差290而已就有整組了阿XD)，&lt;br&gt;
如果你還是想先試試基礎課的話，&lt;br&gt;
&lt;strong&gt;300元折抵的連結&lt;/strong&gt; 在這邊：&lt;br&gt;
&lt;a class="link" href="https://bit.ly/1desolve" target="_blank" rel="noopener"
&gt;https://bit.ly/1desolve&lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 95 Dynamic Programming (12)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-95-dynamic-programming-12/</link><pubDate>Sat, 06 Jun 2020 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-95-dynamic-programming-12/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 95 Dynamic Programming (12)" /&gt;&lt;p&gt;&lt;strong&gt;1143. Longest Common Subsequence (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="寫在前面"&gt;寫在前面
&lt;/h2&gt;&lt;p&gt;容筆者工商一下，&lt;br&gt;
接下來**「從Leetcode學演算法｜進階篇」** 即將於&lt;strong&gt;6/9&lt;/strong&gt; 開放預購啦！&lt;br&gt;
這次選了40道難度加深的LeetCode題目，&lt;br&gt;
同樣也會細部解說對應的技巧及須要掌握的演算法！&lt;br&gt;
同時這次購買進階篇的話，&lt;br&gt;
額外還加贈**「從Leetcode學演算法｜面試篇」** ！&lt;br&gt;
當中包含了面試準備須知分享，及訪談&lt;strong&gt;國內外不同經驗的工程師&lt;/strong&gt; ，&lt;br&gt;
讓你不論是&lt;strong&gt;想走前端/後端/一般軟工&lt;/strong&gt; 或者是&lt;strong&gt;想找國外的工作&lt;/strong&gt; ，&lt;br&gt;
是&lt;strong&gt;初學想轉職&lt;/strong&gt; 還是&lt;strong&gt;正在工作&lt;/strong&gt; ，都能夠從中得到收穫呦！&lt;br&gt;
有興趣的朋友請留意下一篇貼文的早鳥優惠～&lt;/p&gt;
&lt;p&gt;另外，&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given two strings &lt;code&gt;text1&lt;/code&gt; and &lt;code&gt;text2&lt;/code&gt;, return the length of their longest common subsequence.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;subsequence&lt;/em&gt; of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, “ace” is a subsequence of “abcde” while “aec” is not). A &lt;em&gt;common subsequence&lt;/em&gt; of two strings is a subsequence that is common to both strings.&lt;/p&gt;
&lt;p&gt;If there is no common subsequence, return 0.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: text1 = &amp;#34;abcde&amp;#34;, text2 = &amp;#34;ace&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: The longest common subsequence is &amp;#34;ace&amp;#34; and its length is 3.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: text1 = &amp;#34;abc&amp;#34;, text2 = &amp;#34;abc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: The longest common subsequence is &amp;#34;abc&amp;#34; and its length is 3.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-3"&gt;Example 3
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: text1 = &amp;#34;abc&amp;#34;, text2 = &amp;#34;def&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: There is no such common subsequence, so the result is 0.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="constraints"&gt;Constraints
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= text1.length &amp;lt;= 1000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= text2.length &amp;lt;= 1000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The input strings consist of lowercase English characters only.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;給定兩個字串text1及text2，&lt;br&gt;
回傳他們的最長共同子序列(Logest Common Subsequence, LCS)。&lt;br&gt;
一個字串的子序列是指一個字串從字串中原始的一些字母得來，&lt;br&gt;
當中刪去原字串的一些字元(也可以都不刪)，&lt;br&gt;
但保持相對於在原字串中的排列順序。&lt;br&gt;
&lt;strong&gt;舉例來說&lt;/strong&gt; ，&lt;strong&gt;”ace&lt;/strong&gt; ”是**”a** b&lt;strong&gt;c&lt;/strong&gt; d&lt;strong&gt;e”&lt;/strong&gt; 的子序列，但”a&lt;strong&gt;e&lt;/strong&gt; c”不是。&lt;br&gt;
(排列相對順序已經不一樣了)&lt;br&gt;
兩個字串的共同子序列是指這個字串分別都是兩個字串的子序列。&lt;/p&gt;
&lt;p&gt;如果沒有共同子序列，則回傳0。&lt;/p&gt;
&lt;p&gt;當我們看到題目乍看之下沒有明顯的簡單解法時，&lt;br&gt;
就要考慮一下先找出&lt;strong&gt;前後之間的關聯&lt;/strong&gt; 。&lt;br&gt;
也就是說，&lt;br&gt;
我們要先考慮從某一步推往下一步的算式。&lt;/p&gt;
&lt;p&gt;由於我們要求的是LCS，這個要求對應順序的特性，&lt;br&gt;
會導致一點：&lt;br&gt;
&lt;strong&gt;前面經過的字母，後面就不能用了。&lt;/strong&gt; 比方說&amp;quot;&lt;strong&gt;abec&lt;/strong&gt; drr&amp;quot;跟”&lt;strong&gt;ac&lt;/strong&gt; e”，假設我們已經找到了 a 跟 c ，&lt;br&gt;
接下來我們只會從”drr”跟”e”之間作找尋，&lt;br&gt;
因為&amp;quot;abec&amp;quot;中的 e 沒辦法跟第二個字串對應(順序會亂掉)。&lt;br&gt;
這也表示，分別對兩個字串取出兩個子字串的LCS，&lt;br&gt;
&lt;strong&gt;只會跟它們更前面的部分有關聯&lt;/strong&gt; ，而和後面的字元沒有關係。&lt;br&gt;
思考到這裡，顯然這極有可能是Dynamic Programming了XD&lt;/p&gt;
&lt;p&gt;那麼，我們不妨將t1和t2兩個子字串的記法用 i 和 j 表示，&lt;br&gt;
當中0代表完全空字串，最大則分別到l1, l2。&lt;br&gt;
(也就是i, j就代表現在在t1, t2的第幾個字元，&lt;strong&gt;從1開始&lt;/strong&gt; )&lt;br&gt;
我們假設每個值互相關聯，那麼可以寫成一個二維陣列或串列dp。&lt;br&gt;
所以我們知道dp[0][0] == dp[i][0] == dp[0][j] == 0。&lt;br&gt;
(因為至少有一邊是空字串)&lt;br&gt;
下一步呢？&lt;br&gt;
如果我們在分別取 i, j 的字元數，那麼會分兩種狀況：&lt;br&gt;
&lt;strong&gt;1. t1[i-1] == t2[j-1] (i, j 的位置上的字元一模一樣)&lt;/strong&gt;&lt;br&gt;
=&amp;gt; &lt;strong&gt;dp[i][j] = dp[i-1][j-1] + 1&lt;/strong&gt; 因為對應的位置上得到相同字元，所以可以納入子序列中，&lt;br&gt;
所以假設我們知道dp[i-1][j-1]，那麼dp[i][j]應該就恰好多1。&lt;/p&gt;
&lt;p&gt;*這邊很容易搞混，請留意因為計算 index 的時候是從&lt;strong&gt;0&lt;/strong&gt; 開始，&lt;br&gt;
所以我們的&lt;strong&gt;dp[i][j]&lt;/strong&gt; 指的是比較 t1 的 &lt;strong&gt;0 到 i-1&lt;/strong&gt; 及 ** t2** 的 ** 0 到 j-1兩個子字串。**&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. i, j位置上的字元不同 =&amp;gt; 往回推一個字元&lt;br&gt;
由於i, j上的字元不同，所以dp[i][j]要嘛和dp[i][j-1]相同，&lt;br&gt;
要嘛和dp[i-1][j]相同。&lt;strong&gt;也就是說，兩個子字串其中一個&lt;/strong&gt; 往回退一格&lt;/strong&gt;所得到的結果，&lt;br&gt;
當中&lt;strong&gt;取比較大&lt;/strong&gt; 的就可以了。(因為我們在找最大的解嘛XD)&lt;/p&gt;
&lt;p&gt;為什麼不能同時退？&lt;br&gt;
因為可能一邊對到的是前一個阿！&lt;br&gt;
比方說：&lt;br&gt;
“&lt;strong&gt;a&lt;/strong&gt; b&lt;strong&gt;ce&lt;/strong&gt; ffz”跟”&lt;strong&gt;ac&lt;/strong&gt; rrr&lt;strong&gt;e”，&lt;/strong&gt; 假設我們現在正在比較”abcef”跟”acrrre”，&lt;br&gt;
由於f和e不一樣，所以我們要改成比較&amp;quot;abc&lt;strong&gt;e&lt;/strong&gt; &amp;ldquo;-”acrrr&lt;strong&gt;e&lt;/strong&gt; ”和”abce&lt;strong&gt;f&lt;/strong&gt; ”-”acrr&lt;strong&gt;r&lt;/strong&gt; ”。&lt;br&gt;
如果我們直接各退一格，去比較”abce”跟&amp;quot;acrrr&amp;rdquo;，&lt;br&gt;
那e的對應不就被我們去掉了嗎？所以顯然要去除掉沒有對應到的字元，&lt;br&gt;
一次只能從其中一邊倒退一格才行。&lt;/p&gt;
&lt;p&gt;按照這個方式，我們可以使用雙層的迴圈，&lt;br&gt;
就可以將整個dp陣列或串列算完，最終dp[l1][l2]就會是我們想要的答案。&lt;/p&gt;
&lt;p&gt;回顧一下，我們利用了&lt;strong&gt;順序必須不變&lt;/strong&gt; 的特性，&lt;br&gt;
確定了某個位置的值&lt;strong&gt;只跟前面的結果&lt;/strong&gt; 有關；&lt;br&gt;
接著，判定當下&lt;strong&gt;對到的字元是否相同&lt;/strong&gt; ，&lt;br&gt;
&lt;strong&gt;相同的話&lt;/strong&gt; 可以計入並用&lt;strong&gt;各自的前一格&lt;/strong&gt; 的結果表示，&lt;br&gt;
&lt;strong&gt;不同的話&lt;/strong&gt; 則要&lt;strong&gt;看誰退一格比較好&lt;/strong&gt; 。&lt;br&gt;
因此所有的值彼此環環相扣，某個位置的值可以用前面的位置的值來表達，&lt;br&gt;
所以這的確是&lt;strong&gt;動態規劃&lt;/strong&gt; 的問題無誤。&lt;/p&gt;
&lt;p&gt;依此，寫成程式碼如下：&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;Java的部分除了要留意index的計算不要搞錯以外，&lt;br&gt;
整個程式碼相當簡單。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/94081b4e07316ddde30b741fcbea6fb8.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分不要忘記二維串列不要連續用 * 的方式，&lt;br&gt;
(記憶體使用會重疊而不是開新的串列，這個之前有提到過)&lt;br&gt;
其他基本一模一樣。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/69e75a7085dbf609d186a1edf5967951.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(l1 * l2), O(l1 * l2))&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;這題依照不同的起始方式，解也有不同的寫法，&lt;br&gt;
讀者可以嘗試看看有沒有別的寫法。&lt;br&gt;
同時，讀者可能會發現只要前一層的數據，&lt;br&gt;
就可以拿來算下一層了，那麼，儲存的空間可以再進行精簡，&lt;br&gt;
請想想看，這樣子空間複雜度會變成多少呢？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;
&lt;p&gt;感謝大家對這系列文章的支持！這邊跟大家自我工商一下：&lt;/p&gt;
&lt;p&gt;筆者開設的系列同名線上課程：&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜基礎篇」已經快回原價啦！&lt;/strong&gt; 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，&lt;br&gt;
並實際完整練習&lt;strong&gt;20題&lt;/strong&gt; 精選考古題，&lt;br&gt;
進而逐漸提升到不需提示也可以突破白板題，取得工作門票！&lt;/p&gt;
&lt;p&gt;想要一次全包的話，請等待下一篇貼文提供的&lt;strong&gt;同捆包&lt;/strong&gt; XD&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果不太確定這是不是你想要的，&lt;br&gt;
底下是最後一波優惠連結(下次就回原價囉)：&lt;/strong&gt; &lt;a class="link" href="https://hiskio.com/courses/319?promo_code=VE9Q5VE" target="_blank" rel="noopener"
&gt;** https://hiskio.com/courses/319?promo_code=VE9Q5VE**&lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 90 Dynamic Programming (11) / DFS (9)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/</link><pubDate>Sun, 22 Mar 2020 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 90 Dynamic Programming (11) / DFS (9)" /&gt;&lt;p&gt;&lt;strong&gt;0576. Out of Boundary Paths (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;There is an &lt;strong&gt;m&lt;/strong&gt; by ** n** grid with a ball. Given the start coordinate ** (i,j)** of the ball, you can move the ball to an ** adjacent** cell or cross the grid boundary in four directions (up, down, left, right). However, you can ** at most** move ** N** times. Find out the number of paths to move the ball out of the grid boundary. The answer may be very large, return it after mod 10⁹ + 7.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: m = 2, n = 2, N = 2, i = 0, j = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/image-001.png"
width="800"
height="473"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/image-001_hu_213c7b39062f876a.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/image-001_hu_9a760414bfacc3bc.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="169"
data-flex-basis="405px"
&gt;&lt;/p&gt;
&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: m = 1, n = 3, N = 3, i = 0, j = 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 12
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/image-002.png"
width="756"
height="443"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/image-002_hu_da207eaa06da7ecb.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/image-002_hu_d3c59730ae8bf61d.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="170"
data-flex-basis="409px"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Once you move the ball out of the boundary, you cannot move it back.&lt;/li&gt;
&lt;li&gt;The length and height of the grid are in the range [1,50].&lt;/li&gt;
&lt;li&gt;N is in range [0,50].&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;題目描述有一組 m * n 的方格，格子上有一個球，其起始座標為 (i, j)，&lt;br&gt;
你可以將球移到四個方向內沒超過邊界的格子，但最多只能移動N次。&lt;br&gt;
試算出所有會將球移超過邊界的路徑數目。&lt;br&gt;
限制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一旦移出邊界就不能再回來(也就是直接遊戲結束了)&lt;/li&gt;
&lt;li&gt;格子的寬高均在1~50的範圍&lt;/li&gt;
&lt;li&gt;總次數N在0~50的範圍&lt;br&gt;
另由於答案可能非常大，回傳結果要先&lt;strong&gt;除以10的9次方+7。&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我們先思考關於路徑超過邊界的狀態。&lt;br&gt;
要被算做是其中一種的話，首先最後一步一定要是從&lt;strong&gt;格子內移到格子外&lt;/strong&gt; ，&lt;br&gt;
也就是要在邊界才可以，只差一格index就&lt;strong&gt;小於0&lt;/strong&gt; 或**&amp;gt;m-1** (或&lt;strong&gt;n-1&lt;/strong&gt; )。&lt;br&gt;
畢竟不在懸崖邊怎麼可能會有掉下懸崖的可能對吧XD！&lt;br&gt;
並且，因為&lt;strong&gt;掉下去就回不來了&lt;/strong&gt; ，所以路徑就會到此為止。&lt;br&gt;
(當然不管剩下的步數，你總不會飛簷走壁吧@@)&lt;/p&gt;
&lt;p&gt;接著，當 &lt;strong&gt;N=0&lt;/strong&gt; 時，&lt;br&gt;
&lt;strong&gt;由於根本沒辦法動，自然不會有符合的路徑&lt;/strong&gt; ，答案為0。&lt;br&gt;
&lt;strong&gt;N = 1&lt;/strong&gt; 時，則要** 看你四邊有幾個懸崖&lt;strong&gt;對吧！&lt;br&gt;
那N = 2呢？&lt;br&gt;
是不是就要先看&lt;/strong&gt;這一步有幾種可能會掉下去，加總起來以後** ，&lt;br&gt;
接下來&lt;strong&gt;先走到不會掉下去的地方，再看那幾個有幾種情況會掉下去。&lt;br&gt;
由於每走一步路，可用的步數就會少1&lt;/strong&gt;，&lt;br&gt;
我們終究會&lt;strong&gt;要嘛掉下去&lt;/strong&gt; ，&lt;strong&gt;要嘛走到沒有步數可用；&lt;/strong&gt;&lt;br&gt;
將所有加總起來，就得到答案了。&lt;/p&gt;
&lt;p&gt;這個方式聽起來很DFS對吧？&lt;br&gt;
所以按照上面的直覺，也許你會寫成像這樣子的內容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;12
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Will TLE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;class Solution:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; def findPaths(self, m: int, n: int, N: int, i: int, j: int) -&amp;gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; def dfs(i, j, N):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if N != 0:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res += 1 if i - 1 &amp;lt; 0 else dfs(i-1, j, N-1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res += 1 if i + 1 == m else dfs(i+1, j, N-1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res += 1 if j - 1 &amp;lt; 0 else dfs(i, j-1, N-1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res += 1 if j + 1 == n else dfs(i, j+1, N-1)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return res
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res = dfs(i, j, N)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return res % (10 ** 9 + 7)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;當方向會掉下去的時候，就代表方法數加1；&lt;br&gt;
否則的話，就要往那個方向走1步去算可能的方法。&lt;br&gt;
你會發現測試一般的結果可以算出正確答案，&lt;br&gt;
但大一點的數字會算到超時，為什麼呢？&lt;/p&gt;
&lt;p&gt;其實理由跟以前我們算Fibonacci數列時一樣，&lt;br&gt;
這樣子的寫法會導致每一個數都是從單一個1累加起來的，&lt;br&gt;
中間我們可能走到同樣的格子，剩下相同的步數，&lt;br&gt;
卻沒有利用到這點，從而導致效率超級差。&lt;/p&gt;
&lt;p&gt;那怎麼辦呢？&lt;br&gt;
當我們同時考慮動態規劃的觀念時，&lt;br&gt;
就容易想到，我們可以將先前算過的東西當成已知的內容儲存起來，&lt;br&gt;
當再碰到時，就可以直接取用計算。&lt;br&gt;
在本例當中，影響到結果的值有i, j, N，&lt;br&gt;
所以我們可以選擇使用&lt;strong&gt;一個三維的陣列/串列&lt;/strong&gt; ，(也可以用兩個二維陣列)&lt;br&gt;
或者Python內也可以用&lt;strong&gt;字典&lt;/strong&gt; 來做對應儲存。&lt;br&gt;
扣除掉這點以外，跟前面的寫法並無不同，讀者可以自行參照看看。&lt;/p&gt;
&lt;p&gt;那麼，有沒有別種思考的方式呢？&lt;br&gt;
有的，像是lee215就提供了另一種思路：&lt;br&gt;
我們最開始N=0時，整個盤面不論i, j為什麼，&lt;br&gt;
(i, j, 0)的結果都會是0，而(i, j, N)的結果，&lt;br&gt;
則取決於**(i, j)上下左右4格在N-1步的時候** 的結果。&lt;br&gt;
如果該格超出邊界，則至少從(i, j)有1步可以走出邊界，&lt;br&gt;
反之，(i, j)可以花1步走過去。&lt;br&gt;
因此，我們可以一次一次更新整個盤面，&lt;br&gt;
從而算得第N步的結果。(&lt;strong&gt;參見Python lee215解&lt;/strong&gt; )&lt;/p&gt;
&lt;p&gt;或者，我們也可以從i, j為起點，&lt;br&gt;
記錄從&lt;strong&gt;i, j到某一格的總路徑數量&lt;/strong&gt; ，&lt;br&gt;
&lt;strong&gt;每當有機會超出邊界時，則將該部分加總到結果中，&lt;br&gt;
兩個方法殊途同歸，最後都可以得到解答。(參見Java shawngao解)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;依照上面的這些想法，我們可以寫成解答：&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;在Java的部分，除了上面提過的遞進計算整個盤面，&lt;br&gt;
(使用兩個二維陣列交替)&lt;br&gt;
也可以用三維陣列去記錄結果，&lt;br&gt;
留意為了要偵測是否有記錄結果，&lt;br&gt;
我們要用Arrays.fill()，將初始化的陣列都填入-1，&lt;br&gt;
這樣我們才知道這個值它是0還是未填入的狀態。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/0f38d843a1cec840a22f7c2b6855078e.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分，除了lee215的解法外，&lt;br&gt;
我們也可以如上面提到的採用一個字典來進行儲存先前已計算過的內容。&lt;br&gt;
此外，由於在這個問題中，&lt;br&gt;
鏡像對稱位置的點在相同的N值下應該會有相同的答案，&lt;br&gt;
所以還可以透過對稱的方式來進一步化簡所需的計算數量。&lt;br&gt;
(可以看註解底下最後一個解，65~69行的部分)&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/c116a47b873399929e841da0e7b405b3.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(時間複雜度方面，原則上最壞的狀況就是每個步驟算完整個盤面，&lt;br&gt;
所以會是&lt;strong&gt;O(m*n*N)&lt;/strong&gt; 。&lt;br&gt;
空間複雜度的話，使用&lt;strong&gt;三維陣列或字典&lt;/strong&gt; 的話是&lt;strong&gt;O(m*n*N)&lt;/strong&gt; ，&lt;br&gt;
而使用&lt;strong&gt;兩個二維陣列交替記錄&lt;/strong&gt; 的話則是&lt;strong&gt;O(m*n)&lt;/strong&gt; )&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;
&lt;p&gt;感謝大家對這系列文章的支持！這邊跟大家自我工商一下：&lt;/p&gt;
&lt;p&gt;筆者開設的系列同名線上課程：&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜基礎篇」已經上線啦！&lt;/strong&gt; 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，&lt;br&gt;
並實際完整練習&lt;strong&gt;20題&lt;/strong&gt; 精選考古題，&lt;br&gt;
進而逐漸提升到不需提示也可以突破白板題，取得工作門票！&lt;br&gt;
&lt;strong&gt;Medium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)：&lt;/strong&gt; &lt;a class="link" href="https://hiskio.com/courses/319?promo_code=VE9Q5VE" target="_blank" rel="noopener"
&gt;** https://hiskio.com/courses/319?promo_code=VE9Q5VE**&lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 83 Dynamic Programming (10)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-83-dynamic-programming-10/</link><pubDate>Wed, 15 Jan 2020 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-83-dynamic-programming-10/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 83 Dynamic Programming (10)" /&gt;&lt;p&gt;&lt;strong&gt;0091. Decode Ways (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;A message containing letters from &lt;code&gt;A-Z&lt;/code&gt; is being encoded to numbers using the following mapping:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#39;A&amp;#39; -&amp;gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#39;B&amp;#39; -&amp;gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#39;Z&amp;#39; -&amp;gt; 26
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Given a &lt;strong&gt;non-empty&lt;/strong&gt; string containing only digits, determine the total number of ways to decode it.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: &amp;#34;12&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: It could be decoded as &amp;#34;AB&amp;#34; (1 2) or &amp;#34;L&amp;#34; (12).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: &amp;#34;226&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: It could be decoded as &amp;#34;BZ&amp;#34; (2 26), &amp;#34;VF&amp;#34; (22 6), or &amp;#34;BBF&amp;#34; (2 2 6).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;給定一個訊息，當中A到Z以1至26的方式依序對應，&lt;br&gt;
用數字的編碼方式寫成一個字串。&lt;br&gt;
給定這樣子一個僅含數字1~9組成的字串，&lt;br&gt;
試決定所有可以解碼的方法數。&lt;/p&gt;
&lt;p&gt;這題在LeetCode上面比較有問題的點在於，&lt;br&gt;
沒有硬性規定&lt;strong&gt;開頭或結尾多出來的0&lt;/strong&gt; 的部分。&lt;br&gt;
所以這邊我們會再加上一個條件，&lt;br&gt;
&lt;strong&gt;一旦開頭有0或中間有碰到多餘的0&lt;/strong&gt; 的部分，&lt;br&gt;
就當作可以接續下去(不當作錯誤)，&lt;br&gt;
這樣看起來會比較符合測資測出來的結果。&lt;/p&gt;
&lt;p&gt;首先會考慮到就當下而言，如果是空字串的話，&lt;br&gt;
應該要直接先回傳0**(雖然沒有字串嚴格來說也是1種方法，&lt;br&gt;
但給題目來說就要代表沒有辦法解碼)&lt;strong&gt;。&lt;br&gt;
如果是考慮每個字串起始檢查的狀況，&lt;br&gt;
則應該會將起始條件設定為&lt;/strong&gt;1種可能。**&lt;/p&gt;
&lt;p&gt;接下來我們考慮往下走的時候，怎麼樣可以構成可能的字組呢？&lt;br&gt;
我們假定從index 0開始的各種子字串，&lt;br&gt;
均已知有幾種方法了，那麼，當我們在index i的位置時，&lt;br&gt;
要如何決定到這邊的方法數呢？其實不難思考。&lt;/p&gt;
&lt;p&gt;由於我們的英文字母可能性是從1&lt;del&gt;26，&lt;br&gt;
所以如果**index i對應的值是1&lt;/del&gt;9之間** 的話，&lt;br&gt;
代表它獨立可以成為一種可能性，&lt;br&gt;
也就是&lt;strong&gt;走到前面i-1的狀況，再加上i這邊單獨代表的字母&lt;/strong&gt; 。&lt;br&gt;
這麼考慮的話&lt;strong&gt;走到i的組合數就和走到i-1的組合數是相同的&lt;/strong&gt; 。&lt;br&gt;
(以index i位置的值單獨成立的狀況來說)&lt;/p&gt;
&lt;p&gt;那麼還有另一種可能，&lt;br&gt;
就是index i-1和index i所組成的二位數也能代表字母，&lt;br&gt;
這個數字應該是&lt;strong&gt;10~26&lt;/strong&gt; 之間，所以這種狀況成立的條件下，&lt;br&gt;
&lt;strong&gt;走到i的組合數和走到i-2的組合數相同&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;所以歸納上述兩點，我們必須要分別檢查，&lt;br&gt;
然後決定是否要將i-1的方法數及i-2的方法數加進來。&lt;/p&gt;
&lt;p&gt;感覺是不是有點像之前的House Robber?&lt;br&gt;
所以這也是一個典型的Dynamic Programming題目。&lt;br&gt;
依此，我們可以定一個array或list，取名叫&lt;strong&gt;dp&lt;/strong&gt; ，&lt;br&gt;
&lt;strong&gt;長度為s的長度加1。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我們將可能的兩位數分別叫做prev跟curr，&lt;br&gt;
那麼每次要作的事情，就如同上面所述一樣：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;初始化&lt;strong&gt;dp[0] = 1&lt;/strong&gt; , &lt;br&gt;
&lt;strong&gt;dp[1] = 1 (如果第一個字不是'0&amp;rsquo;) or 0 (如果第一個字是'0&amp;rsquo;)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;迴圈讓i從2&lt;del&gt;l，&lt;br&gt;
每次將&lt;strong&gt;curr的值遞移到prev，prev則取得s[i-1]&lt;/strong&gt; 的值。&lt;br&gt;
當&lt;strong&gt;curr非0&lt;/strong&gt; 的時候(即1&lt;/del&gt;9)，我們可以將&lt;strong&gt;dp[i-1]加到dp[i]&lt;/strong&gt; 中；&lt;br&gt;
當&lt;strong&gt;prev和curr&lt;/strong&gt; 可以組成&lt;strong&gt;10~26之間&lt;/strong&gt; 的值時，可以將&lt;strong&gt;dp[i-2]加到dp[i]&lt;/strong&gt; 中。&lt;/li&gt;
&lt;li&gt;迴圈結束後，回傳&lt;strong&gt;dp[l]&lt;/strong&gt; 即可。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;依此，寫成程式碼如下。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;Java的部分，也可以順便檢查s是否為null，&lt;br&gt;
但本題的測資似乎也沒有刁難這個部分(題目有說均為數字)。&lt;br&gt;
檢查&lt;strong&gt;10~26&lt;/strong&gt; 的部分，&lt;br&gt;
可以拆成(&lt;strong&gt;prev==’1’)&lt;/strong&gt; 或(&lt;strong&gt;prev == ‘2’且curr ≤ ’6’)&lt;/strong&gt; 檢驗。 &lt;strong&gt;對Java而言，&lt;br&gt;
char可以直接用數字的方式(ASCII Code)的狀態來比大小，&lt;br&gt;
所以我們不用再轉成Integer來浪費時間XD&lt;/strong&gt;&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/e75f8c280ddae8ee783551388dd09009.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分，也可以&lt;strong&gt;直接比大小&lt;/strong&gt; ，其實作是呼叫ord()函數，&lt;br&gt;
來取得比大小所需的ASCII Code數字，&lt;br&gt;
但就沒辦法像Java的char那樣很多花樣了。&lt;/p&gt;
&lt;p&gt;提醒大家，在寫的時候請務必留意範圍，&lt;br&gt;
以本題為例，由於&lt;strong&gt;dp[0]&lt;/strong&gt; 是被佔用做為初始值的，&lt;br&gt;
所以我們在寫的時候&lt;strong&gt;i是對應由1為準起算的。&lt;/strong&gt;&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/51589115429e6a36335017a990c03510.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(N)/O(N)，N為字串長度)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;
&lt;p&gt;感謝大家對這系列文章的支持！這邊跟大家自我工商一下：&lt;/p&gt;
&lt;p&gt;筆者開設的系列同名線上課程：&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜基礎篇」已經上線啦！&lt;/strong&gt; 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，&lt;br&gt;
並實際完整練習&lt;strong&gt;20題&lt;/strong&gt; 精選考古題，&lt;br&gt;
進而逐漸提升到不需提示也可以突破白板題，取得工作門票！&lt;br&gt;
&lt;strong&gt;Medium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)：&lt;/strong&gt; &lt;a class="link" href="https://hiskio.com/courses/319?promo_code=VE9Q5VE" target="_blank" rel="noopener"
&gt;** https://hiskio.com/courses/319?promo_code=VE9Q5VE**&lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 61 Dynamic Programming (9)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-61-dynamic-programming-9/</link><pubDate>Sun, 13 Oct 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-61-dynamic-programming-9/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 61 Dynamic Programming (9)" /&gt;&lt;p&gt;&lt;strong&gt;1140. Stone Game II (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="寫在前面"&gt;寫在前面
&lt;/h2&gt;&lt;p&gt;大家連假過的好嗎XD？筆者到新加坡玩了一趟，不好意思好幾天沒更新啦~&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Alex and Lee continue their games with piles of stones. There are a number of piles &lt;strong&gt;arranged in a row&lt;/strong&gt; , and each pile has a positive integer number of stones &lt;code&gt;piles[i]&lt;/code&gt;. The objective of the game is to end with the most stones.&lt;/p&gt;
&lt;p&gt;Alex and Lee take turns, with Alex starting first. Initially, &lt;code&gt;M = 1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On each player’s turn, that player can take &lt;strong&gt;all the stones&lt;/strong&gt; in the ** first** &lt;code&gt;X&lt;/code&gt; remaining piles, where &lt;code&gt;1 &amp;lt;= X &amp;lt;= 2M&lt;/code&gt;. Then, we set &lt;code&gt;M = max(M, X)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The game continues until all the stones have been taken.&lt;/p&gt;
&lt;p&gt;Assuming Alex and Lee play optimally, return the maximum number of stones Alex can get.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: piles = [2,7,9,4,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: If Alex takes one pile at the beginning, Lee takes two piles, then Alex takes 2 piles again. Alex can get 2 + 4 + 4 = 10 piles in total. If Alex takes two piles at the beginning, then Lee can take all three piles left. In this case, Alex get 2 + 7 = 9 piles in total. So we return 10 since it&amp;#39;s larger.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="constraints"&gt;Constraints
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= piles.length &amp;lt;= 100&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= piles[i] &amp;lt;= 10 ^ 4&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;聽說之前有人一直嗆說怎麼都沒人能夠將1140這題講清楚？&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-61-dynamic-programming-9/image-001.png"
width="225"
height="225"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-61-dynamic-programming-9/image-001_hu_34d874b3418cdf09.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-61-dynamic-programming-9/image-001_hu_edcc7361dca0d91.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="100"
data-flex-basis="240px"
&gt;&lt;/p&gt;
&lt;p&gt;這題其實題目不難理解：&lt;br&gt;
Alex和Lee兩個人玩搶石頭的遊戲，石頭被分成數堆，&lt;br&gt;
使用piles[i]來記錄，遊戲目的是在結尾時拿到最多的石頭。&lt;br&gt;
Alex和Lee輪流拿石頭(&lt;strong&gt;Alex先&lt;/strong&gt; )，&lt;strong&gt;最開始的時候M設定為1&lt;/strong&gt; 。&lt;br&gt;
每次玩家要決定拿剩下的&lt;strong&gt;前X堆的所有石頭&lt;/strong&gt; (必須按順序&lt;strong&gt;不可以跳過&lt;/strong&gt; )，&lt;br&gt;
X的範圍是1 ≤ X ≤ 2M；接下來就要依照X來更新M：&lt;strong&gt;M = max(M, X)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;直到所有石頭都被拿光，遊戲就結束了。&lt;br&gt;
假定Alex和Lee都以最佳化的狀況來玩這個遊戲(play optimally)，&lt;br&gt;
回傳Alex在遊戲結束時最多能拿到的石頭。&lt;/p&gt;
&lt;p&gt;在所謂&amp;quot;play optimally&amp;quot;的遊戲中，&lt;br&gt;
我們會假設參與的玩家都清楚&lt;strong&gt;知道所有人的策略&lt;/strong&gt; ，&lt;br&gt;
並且&lt;strong&gt;選擇對自己利益最大的選擇&lt;/strong&gt; 。&lt;br&gt;
依照這樣子的概念，我們其實可以感覺到前後會有所關聯，&lt;br&gt;
因為對於雙方來說都是想要&lt;strong&gt;最大化自己拿到的石頭&lt;/strong&gt; ；&lt;br&gt;
又，&lt;strong&gt;自己拿到最多，就意味著對方拿到最少&lt;/strong&gt; ，&lt;br&gt;
所以這點同時還隱含了中間的可能會有一些判斷，&lt;br&gt;
比如像是X這類型的變數對於同樣從第i堆開始來說，&lt;br&gt;
要走哪個方向又會都有各自的分支，需要好好考慮才行。&lt;/p&gt;
&lt;p&gt;我們先假定有一個函數dp，&lt;br&gt;
這個函數可以計算當現在要從pile[i]開始拿的時候，&lt;br&gt;
(也就是0~i-1堆都被拿光了)&lt;br&gt;
輪到的玩家在這次及這輪以後所能拿到的石頭數的最大值。&lt;br&gt;
顯然這還會有另一個變數M，&lt;br&gt;
因為M能夠決定這輪最大可以拿到的堆數(2M)。&lt;br&gt;
因此我們將這個函數表示成dp(i, M)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先討論一個最簡單的狀況：&lt;/strong&gt;&lt;br&gt;
當&lt;strong&gt;i+2M ≥ n-1&lt;/strong&gt; 的時候，(假設總石頭的堆數是n)&lt;br&gt;
表示這個玩家可以直接選擇&lt;strong&gt;將剩下的石堆全取走&lt;/strong&gt; ，&lt;br&gt;
就會是他所能拿到的石頭量的最大值。&lt;br&gt;
&lt;strong&gt;(因為遊戲就結束了，另一個玩家什麼都拿不到)&lt;/strong&gt;&lt;br&gt;
所以這個就會是這個dp的&lt;strong&gt;確定值&lt;/strong&gt; 的部分了。&lt;/p&gt;
&lt;p&gt;接下來我們討論另一個狀況：(假設是A跟B玩家輪流拿石頭)&lt;br&gt;
假設&lt;strong&gt;A玩家取了x堆&lt;/strong&gt; ，接下來會發生什麼事情呢？&lt;br&gt;
輪到下一個玩家B了，對吧？&lt;br&gt;
那麼玩家要從&lt;strong&gt;i+x堆&lt;/strong&gt; 的位置開始拿取，&lt;br&gt;
而此時的M按照遊戲規則是&lt;strong&gt;max(M,x)&lt;/strong&gt; 。&lt;br&gt;
&lt;strong&gt;由於B同樣也是play optimally&lt;/strong&gt; ，&lt;br&gt;
所以B也想&lt;strong&gt;最大限度的在這整場遊戲中獲得較多的石頭&lt;/strong&gt; ，&lt;br&gt;
故對B而言在i+x堆開始拿取的數字按照定義就是&lt;strong&gt;dp(i+x, max(M,x))&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;那麼關鍵來了：&lt;br&gt;
對於&lt;strong&gt;dp(i,M)&lt;/strong&gt; 而言，固定不變的會是從&lt;strong&gt;pile[i]到最後的石堆的石頭總量&lt;/strong&gt; ，&lt;br&gt;
我們暫時先命名為Si, &lt;strong&gt;Si = pile[i]~ pile[N-1]的和&lt;/strong&gt; 。&lt;br&gt;
所以會變動的就只有B拿的部分而已。&lt;br&gt;
所以我們可以得到&lt;strong&gt;dp(i, M) = Si - dp(i+x, max(M, x))&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;又實際上我們一開始也不知道x應該取多少會最好，&lt;br&gt;
&lt;strong&gt;所以x的範圍一樣是1~2M&lt;/strong&gt; ，也就是我們要在x是這個範圍的所有狀況下，&lt;br&gt;
&lt;strong&gt;找出dp(i+x, max(M, x))的最小值，從而得到dp(i, M)&lt;/strong&gt; 。&lt;br&gt;
(因為&lt;strong&gt;想要A拿的最多，就是要B拿的最少&lt;/strong&gt; ，故要取後者的最小值)&lt;/p&gt;
&lt;p&gt;在實務上，我們可以拿前面的piles來計算Si，只要一路&lt;strong&gt;從尾到頭&lt;/strong&gt; ，&lt;br&gt;
將piles的値往回加即可(因為Si = piles[i]&lt;del&gt;piles[N-1]的和)。&lt;br&gt;
我們需要一個二維陣列dp[][]，&lt;br&gt;
&lt;strong&gt;第一個維度表示i&lt;/strong&gt; (範圍是**0&lt;/del&gt;n-1** )&lt;br&gt;
&lt;strong&gt;第二個維度表示M&lt;/strong&gt; (範圍是&lt;strong&gt;1~(n-1)/2 + 1&lt;/strong&gt; ，但為了方便起見，&lt;br&gt;
我們陣列只使用1開始的部分以避免位移，&lt;br&gt;
所以再加一以後，我們第二維的長度會是**(n+1)/2 + 1** )&lt;/p&gt;
&lt;p&gt;我們整理一下實際的演算流程。&lt;br&gt;
&lt;strong&gt;主函式中:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;從尾到頭&lt;/strong&gt; 將&lt;strong&gt;piles[i+1]&lt;/strong&gt; 加到&lt;strong&gt;piles[i]&lt;/strong&gt; 上，&lt;br&gt;
讓&lt;strong&gt;piles[i]現在代表從第i堆開始的所有石頭數&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;新增一個二維陣列&lt;strong&gt;dp[][]&lt;/strong&gt; 以表示在**(i, M)** 條件下所能取得石頭的最大値。&lt;/li&gt;
&lt;li&gt;呼叫helper函式來&lt;strong&gt;遞迴&lt;/strong&gt; 處理。&lt;br&gt;
&lt;strong&gt;在helper函式中:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如果i已經走超過了則&lt;strong&gt;回傳0&lt;/strong&gt; (表遊戲結束)&lt;/li&gt;
&lt;li&gt;如果2*M &amp;gt;= len(piles) - i則回傳&lt;strong&gt;piles[i]&lt;/strong&gt; (&lt;strong&gt;一口氣取完剩下的石頭&lt;/strong&gt; )&lt;/li&gt;
&lt;li&gt;當dp[i][M]尚未被計算出値的時候，&lt;br&gt;
&lt;strong&gt;遞迴搜尋dp[i+x][max(M,x)]的最小值&lt;/strong&gt; ，(x範圍是1~2*M)&lt;br&gt;
(已知値的話則直接代入)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dp[i][M]等於piles[i]減去前述的最小值&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回傳dp[i][M]&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;依此，寫成程式碼：&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/70f5ac33c747358d2012c394e6e8a29d.js"&gt;&lt;/script&gt;
&lt;p&gt;Python的部分，可將遞迴的部分搭配&lt;br&gt;
&lt;strong&gt;for x in range(1, 2 * M + 1)&lt;/strong&gt; 看起來會更簡潔。&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/50316eca545c6342f3ab2ca3e194003c.js"&gt;&lt;/script&gt;
&lt;p&gt;Python的部份根據大神&lt;a class="link" href="https://leetcode.com/problems/stone-game-ii/discuss/345230/Python-DP-Solution" target="_blank" rel="noopener"
&gt;lee215的解答&lt;/a&gt;，還可以做一些簡化：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c6a0f6"&gt;def&lt;/span&gt; &lt;span style="color:#8aadf4"&gt;stoneGameII&lt;/span&gt;(&lt;span style="color:#91d7e3"&gt;self&lt;/span&gt;, A: List[&lt;span style="color:#f5a97f"&gt;int&lt;/span&gt;]) &lt;span style="color:#91d7e3;font-weight:bold"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#f5a97f"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; N &lt;span style="color:#91d7e3;font-weight:bold"&gt;=&lt;/span&gt; len(A)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c6a0f6"&gt;for&lt;/span&gt; i &lt;span style="color:#91d7e3;font-weight:bold"&gt;in&lt;/span&gt; &lt;span style="color:#91d7e3"&gt;range&lt;/span&gt;(N &lt;span style="color:#91d7e3;font-weight:bold"&gt;-&lt;/span&gt; &lt;span style="color:#f5a97f"&gt;2&lt;/span&gt;, &lt;span style="color:#91d7e3;font-weight:bold"&gt;-&lt;/span&gt;&lt;span style="color:#f5a97f"&gt;1&lt;/span&gt;, &lt;span style="color:#91d7e3;font-weight:bold"&gt;-&lt;/span&gt;&lt;span style="color:#f5a97f"&gt;1&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; A[i] &lt;span style="color:#91d7e3;font-weight:bold"&gt;+=&lt;/span&gt; A[i &lt;span style="color:#91d7e3;font-weight:bold"&gt;+&lt;/span&gt; &lt;span style="color:#f5a97f"&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; from functools import lru_cache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ed8796"&gt;@&lt;/span&gt;lru_cache(None)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c6a0f6"&gt;def&lt;/span&gt; &lt;span style="color:#8aadf4"&gt;dp&lt;/span&gt;(i, m):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c6a0f6"&gt;if&lt;/span&gt; i &lt;span style="color:#91d7e3;font-weight:bold"&gt;+&lt;/span&gt; &lt;span style="color:#f5a97f"&gt;2&lt;/span&gt; &lt;span style="color:#91d7e3;font-weight:bold"&gt;*&lt;/span&gt; m &lt;span style="color:#91d7e3;font-weight:bold"&gt;&amp;gt;=&lt;/span&gt; N: &lt;span style="color:#c6a0f6"&gt;return&lt;/span&gt; A[i]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c6a0f6"&gt;return&lt;/span&gt; A[i] &lt;span style="color:#91d7e3;font-weight:bold"&gt;-&lt;/span&gt; &lt;span style="color:#91d7e3"&gt;min&lt;/span&gt;(dp(i &lt;span style="color:#91d7e3;font-weight:bold"&gt;+&lt;/span&gt; x, &lt;span style="color:#91d7e3"&gt;max&lt;/span&gt;(m, x)) &lt;span style="color:#c6a0f6"&gt;for&lt;/span&gt; x &lt;span style="color:#91d7e3;font-weight:bold"&gt;in&lt;/span&gt; &lt;span style="color:#91d7e3"&gt;range&lt;/span&gt;(&lt;span style="color:#f5a97f"&gt;1&lt;/span&gt;, &lt;span style="color:#f5a97f"&gt;2&lt;/span&gt; &lt;span style="color:#91d7e3;font-weight:bold"&gt;*&lt;/span&gt; m &lt;span style="color:#91d7e3;font-weight:bold"&gt;+&lt;/span&gt; &lt;span style="color:#f5a97f"&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c6a0f6"&gt;return&lt;/span&gt; dp(&lt;span style="color:#f5a97f"&gt;0&lt;/span&gt;, &lt;span style="color:#f5a97f"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;lru_cache&lt;/strong&gt; 可以將函式已經計算過的結果直接快取放置在記憶體中，&lt;br&gt;
當再次需要計算値的時候，&lt;strong&gt;不經過計算，直接將値回傳&lt;/strong&gt; 。&lt;/p&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(N³)/O(N²)，因為記錄所有解要對應到二維陣列，&lt;br&gt;
而對於每一個陣列解都需要往下搜尋O(N)的長度來比較得出最小值。)&lt;/p&gt;
&lt;p&gt;「為什麼要記錄一個dp的陣列？&lt;strong&gt;不能直接靠遞迴記錄嗎&lt;/strong&gt; ？」&lt;br&gt;
(遞迴記錄&lt;strong&gt;同樣要使用記憶體空間&lt;/strong&gt; ，且因為中間拆解時，&lt;br&gt;
&lt;strong&gt;可能會有重複的(i, M)出現，不先記錄的話會造成有重複計算的狀況。&lt;/strong&gt; )&lt;/p&gt;
&lt;p&gt;「這題是否可以用迭代法解？」&lt;br&gt;
(可以，請參閱&lt;a class="link" href="https://leetcode.com/problems/stone-game-ii/discuss/355710/Java-simple-DP-solution-with-explanation" target="_blank" rel="noopener"
&gt;yzstone的解法&lt;/a&gt;。)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 37 Dynamic Programming (8)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-37-dynamic-programming-8/</link><pubDate>Thu, 22 Aug 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-37-dynamic-programming-8/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 37 Dynamic Programming (8)" /&gt;&lt;p&gt;&lt;strong&gt;0121. Best Time to Buy and Sell Stock (Easy)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Say you have an array for which the &lt;em&gt;i&lt;/em&gt;th element is the price of a given stock on day &lt;em&gt;i&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.&lt;/p&gt;
&lt;p&gt;Note that you cannot sell a stock before you buy one.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [7,1,5,3,6,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Not 7-1 = 6, as selling price needs to be larger than buying price.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [7,6,4,3,1]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: In this case, no transaction is done, i.e. max profit = 0.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;買股票啦XD~題目給定一個陣列，第i個元素代表day i的股價。&lt;br&gt;
如果你只被允許完成一次交易(買一次然後賣一次)，&lt;br&gt;
嘗試找到最大的利潤為何。&lt;/p&gt;
&lt;p&gt;我們假定我們在某個時間點買了股票，&lt;br&gt;
那獲得的利潤每隔一天，就會變動這兩天的差價值。&lt;br&gt;
我們可以將當下的利潤定為cur，那麼cur不論從哪開始必定為0。&lt;br&gt;
(當天買當天賣)&lt;/p&gt;
&lt;p&gt;假定有一天股價&lt;strong&gt;低於&lt;/strong&gt; 我們買的時候的價格，就表示我們&lt;strong&gt;買貴&lt;/strong&gt; 了，&lt;br&gt;
應該要&lt;strong&gt;從現在這個點開始一定會比前面那個點還好&lt;/strong&gt; ，(買進的價格較低)&lt;br&gt;
我們可以&lt;strong&gt;將cur重設為0(從這個點重新出發)&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;反之如果價格比較高的話，我們可以計算現在的利潤，&lt;br&gt;
並和全局最大值比較後再更新全局最大值。&lt;br&gt;
所以每次依序計算現在的利潤決定是否重新選擇出發點，&lt;br&gt;
再處理好全局最大值的紀錄即可解決此題。&lt;/p&gt;
&lt;p&gt;這邊Java和Python的程式碼僅差別在設定條件的方式不同而已，&lt;br&gt;
但本質一樣是在處理&lt;strong&gt;現有的值&lt;/strong&gt; 及&lt;strong&gt;最大值&lt;/strong&gt; 這兩項。&lt;br&gt;
讀者可以自行選用處理的方式。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/70c5a699ef074023125d11ab2e1e3499.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/7feef22bb492dec05f32bc93a1d4ae39.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(N), O(1)，掃過整個空間一次，除cur跟res外不需其他變數。)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;1.&lt;a class="link" href="https://medium.com/@desolution/%E5%BE%9Eleetcode%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-7-dynamic-programming-d1c3255dc266?source=your_stories_page---------------------------" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0053. Maximum Subarray&lt;/strong&gt; &lt;/a&gt;2. &lt;strong&gt;Best Time to Buy and Sell Stock系列題(XDDDDD)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 29 Dynamic Programming (7)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-29-dynamic-programming-7/</link><pubDate>Mon, 12 Aug 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-29-dynamic-programming-7/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 29 Dynamic Programming (7)" /&gt;&lt;p&gt;&lt;strong&gt;0213. House Robber II (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are &lt;strong&gt;arranged in a circle.&lt;/strong&gt; That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have security system connected and ** it will automatically contact the police if two adjacent houses were broken into on the same night**.&lt;/p&gt;
&lt;p&gt;Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight &lt;strong&gt;without alerting the police&lt;/strong&gt; .&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [2,3,2]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You cannot rob house 1 (money = 2) and then rob house 3 (money = 2),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;because they are adjacent houses.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [1,2,3,1]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rob house 1 (money = 1) and then rob house 3 (money = 3).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Total amount you can rob = 1 + 3 = 4.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;繼上一次&lt;a class="link" href="https://medium.com/@desolution/%E5%BE%9Eleetcode%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-28-dynamic-programming-6-8e5a81a8437d?source=friends_link&amp;amp;sk=d87bd13d5e6a85da75c83222cddc0d60" target="_blank" rel="noopener"
&gt;&lt;strong&gt;偷完一排房子&lt;/strong&gt; &lt;/a&gt;以後，我們決定挑戰更高難度的偷竊XD&lt;br&gt;
(有完沒完啦！)&lt;/p&gt;
&lt;p&gt;保全狀態依舊是相鄰房子連續被偷就會響警報，不同的是，&lt;br&gt;
現在房子的分布是圓形！也就是第一間和最後一間是相鄰的，&lt;br&gt;
這就會造成我們上一次使用的算法會出現問題。&lt;/p&gt;
&lt;p&gt;那麼怎麼辦呢？&lt;br&gt;
第一間和最後一間有關聯是不是？&lt;br&gt;
那我們就來斷開魂結，斷開鎖鏈，斷開一切的牽連吧！(大誤)&lt;/p&gt;
&lt;p&gt;這裡我們為求方便起見，使用0為index開頭來描述，&lt;br&gt;
這樣等一下對照程式碼也比較方便。&lt;br&gt;
我們令nums的總長度為&lt;strong&gt;l&lt;/strong&gt; ，&lt;br&gt;
並且使用&lt;strong&gt;dp[i]&lt;/strong&gt; 來表示偷到index i的房子時當前所能得到的最大金額。&lt;/p&gt;
&lt;p&gt;如何處理index 0跟l-1的關係呢？&lt;br&gt;
針對index 0的話，只會分成&lt;strong&gt;偷&lt;/strong&gt; 或&lt;strong&gt;不偷&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;古語有云：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To rob, or not to rob, that is a question.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;莎士比亞沒有說過&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以我們可以分開來討論。&lt;br&gt;
假設今天無論如何&lt;strong&gt;就是要偷index 0&lt;/strong&gt; 的房子的話，&lt;br&gt;
可以得到以下推論：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;index l-1不能偷&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dp[0] = nums[0], dp[1] = nums[0]&lt;/strong&gt; (偷了0就不能偷1)&lt;/li&gt;
&lt;li&gt;這狀況能得到的最大金額應為&lt;strong&gt;dp[l-2]&lt;/strong&gt; (因l-1不能偷)&lt;br&gt;
這個狀況，我們可以給定2的起始條件並計算到dp[l-2]即可得到最大金額。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;假設今天就是不偷index 0的房子的話，&lt;br&gt;
可以得到以下推論：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;index l-1能不能偷只需要&lt;strong&gt;看index l-2&lt;/strong&gt; 決定要不要偷&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dp[0] = 0, dp[1] = nums[1]&lt;/strong&gt; (因0不偷，dp[1]要選擇偷index 1)&lt;/li&gt;
&lt;li&gt;這狀況能得到的最大金額應為&lt;strong&gt;dp[l-1]&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以依照這兩個狀況拆開來分別計算一次，&lt;br&gt;
將兩個結果比較大小，取較大的即為答案。&lt;/p&gt;
&lt;p&gt;同上一題描述的一樣，&lt;br&gt;
我們可以利用兩個變數及一個暫存變數，來達到dp的效果。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/84b86e3506369af57e23eaa3deda9aaa.js"&gt;&lt;/script&gt;
&lt;p&gt;Python的部分則再額外提供了將迴圈部分包裝成函式的程式碼，&lt;br&gt;
但實測上由於需要呼叫的原因，看起來平均會略慢於未包裝的狀況。&lt;br&gt;
(附在底下註解處，使用者可再多執行幾次試試看)&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/cb5a5b74a7ffcb35e9b704c24cbf27ee.js"&gt;&lt;/script&gt;
&lt;p&gt;所以總體而言，這題的根本在於，當發現有些狀態是互相關聯時，&lt;br&gt;
&lt;strong&gt;嘗試將其進行拆解，從而重新得到線性可計算動態規劃的狀態。&lt;/strong&gt; 再次強調， &lt;strong&gt;DP的精髓在於找到初始狀態，&lt;br&gt;
及找到從一個狀態推展到下一個狀態的方法。&lt;strong&gt;用骨牌來比喻的話，後者相當於&lt;/strong&gt; 骨牌之間的關係&lt;/strong&gt;，&lt;br&gt;
前者則相當於那個&lt;strong&gt;第一個倒下來的骨牌&lt;/strong&gt; 。&lt;/p&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(N), O(1)&lt;br&gt;
這次的範例程式碼已經不用dp陣列來記錄了，&lt;br&gt;
即便需要掃過nums兩次，但時間複雜度還是O(N))&lt;/p&gt;
&lt;p&gt;「如果保安增強，變成只要連續三棟房子內任二棟被偷即會有警報的話？」&lt;br&gt;
(可以嘗試用類似的方式來推導)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;a class="link" href="https://leetcode.com/problems/house-robber-iii/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0337. House Robber III&lt;/strong&gt; &lt;/a&gt;2.&lt;a class="link" href="https://leetcode.com/problems/min-cost-climbing-stairs/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0746. Min Cost Climbing Stairs&lt;/strong&gt; &lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 28 Dynamic Programming (6)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-28-dynamic-programming-6/</link><pubDate>Sat, 10 Aug 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-28-dynamic-programming-6/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 28 Dynamic Programming (6)" /&gt;&lt;p&gt;&lt;strong&gt;0198. House Robber (Easy)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and &lt;strong&gt;it will automatically contact the police if two adjacent houses were broken into on the same night&lt;/strong&gt; .&lt;/p&gt;
&lt;p&gt;Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight &lt;strong&gt;without alerting the police&lt;/strong&gt; .&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [1,2,3,1]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rob house 1 (money = 1) and then rob house 3 (money = 3).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Total amount you can rob = 1 + 3 = 4.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [2,7,9,3,1]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 12
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Total amount you can rob = 2 + 9 + 1 = 12.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;題目描述你是一個專業的強盜，即將進行入室行竊的勾當。&lt;br&gt;
每間房子都存有確定數量的金錢，但唯一的限制是，每間房都有安保設置，只要相鄰的二間房子在同一個晚上被闖入的話，系統就會自動報警。&lt;br&gt;
給定一個用來表示每間房子存放金額的陣列，試求在不驚動警察狀況下，&lt;br&gt;
最大可以獲得的金額。&lt;/p&gt;
&lt;p&gt;看到這個問題的時候，首先就想OS: 一間就報警的話不是最乾脆XD&lt;/p&gt;
&lt;p&gt;好吧，我們假設這個安保真的是有這種漏洞的話，&lt;br&gt;
那麼怎麼偷最好呢？&lt;/p&gt;
&lt;p&gt;由於題目條件的限制，我們先假設一路偷到第i間，&lt;br&gt;
所能獲得的最大金額為rob[i]，rob[i]會受到什麼限制呢？&lt;br&gt;
假設我們走到第i間，&lt;br&gt;
&lt;strong&gt;選擇要偷第i間的話，意味著我們前面不能偷第i-1間&lt;/strong&gt; 。&lt;br&gt;
這種狀況下，我們可以將rob[i]的值拆開來算：&lt;br&gt;
&lt;strong&gt;rob[i] = rob[i-2] + num[i]&lt;/strong&gt;&lt;br&gt;
(選擇不動第i-1間，並偷了第i間，&lt;br&gt;
而在此之前i-2間所能偷到的最大值是rob[i-2])&lt;/p&gt;
&lt;p&gt;那麼，選擇不偷第i間的話，意味著&lt;strong&gt;rob[i] = rob[i-1]&lt;/strong&gt; (因為你沒偷嘛XD)&lt;/p&gt;
&lt;p&gt;既然有這兩種可能，那麼我們就該選當中比較大的，&lt;br&gt;
所以&lt;strong&gt;rob[i] = max(rob[i-1], rob[i-2] + nums[i])&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;讓我們考慮一下最前面的狀況：&lt;br&gt;
rob[0] = nums[0] (第一間不用考慮前面的影響)&lt;br&gt;
rob[1] = max(nums[0], nums[1]) (兩間選一間偷)&lt;/p&gt;
&lt;p&gt;所以接下來我們只需要一路用前面的式子，迴圈從i=2計算到i=n-1，&lt;br&gt;
最後將rob[n-1]回傳即可。&lt;/p&gt;
&lt;p&gt;所以一路下來，讀者會發現有關動態規劃的題目，&lt;br&gt;
一直在做的事情其實就是嘗試&lt;strong&gt;尋找在第n項的解，&lt;br&gt;
和前面的項次之間的關係&lt;/strong&gt;，一旦能找到這個關係，&lt;br&gt;
並能確認初始的條件，就能一路從頭開始計算將其解出。&lt;/p&gt;
&lt;p&gt;在程式碼的部分，我們可以先行考慮nums為空跟長度為1的狀況，&lt;br&gt;
直接回傳結果以節省空間。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/b954ab22d85b03f0902bf18386d04940.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/d83c7c68910e5e456a511e45fa32f743.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(N), O(N)，掃過一次nums陣列，&lt;br&gt;
並且也用相同長度來儲存最大的偷取金額)&lt;/p&gt;
&lt;p&gt;「空間複雜度可以降低嗎？」&lt;br&gt;
(可以！可以觀察出每個rob的值之間的關聯只有和前2個值有關(i-2和i-1)&lt;br&gt;
我們可以使用robprev, robnext搭配一個temp值，&lt;br&gt;
在迴圈中使用類似下面的方式，可以反復更新值，如此一來，&lt;br&gt;
就只需要O(1)的空間就可以解決此題。)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;int tmp = robprev;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;robprev = robnext;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;robnext = Math.max(robprev, tmp + nums[i]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;1.&lt;a class="link" href="https://leetcode.com/problems/house-robber-ii/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0213. House Robber II (Medium)&lt;/strong&gt; &lt;/a&gt; &lt;strong&gt;(從線性變圓形)&lt;/strong&gt; 2. &lt;a class="link" href="https://leetcode.com/problems/house-robber-iii/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0337. House Robber III (Medium)&lt;/strong&gt; &lt;/a&gt; (&lt;strong&gt;變成二元樹&lt;/strong&gt; )&lt;br&gt;
(到底哪個鄉鎮會這樣子蓋房子啦XD)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;From Medium:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Raiy Kuo - 更正Python程式碼尾端，應回傳rob[-1]或rob[l-1]即可。&lt;br&gt;
(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 26 Dynamic Programming (5)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-26-dynamic-programming-5/</link><pubDate>Wed, 07 Aug 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-26-dynamic-programming-5/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 26 Dynamic Programming (5)" /&gt;&lt;p&gt;&lt;strong&gt;0096. Unique Binary Search Trees (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given &lt;em&gt;n&lt;/em&gt;, how many structurally unique &lt;strong&gt;BST’s&lt;/strong&gt; (binary search trees) that store values 1 … &lt;em&gt;n&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Given n = 3, there are a total of 5 unique BST&amp;#39;s:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1 3 3 2 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; \ / / / \ \
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 3 2 1 1 3 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; / / \ \
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2 1 2 3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;還記得什麼是二元搜尋樹嗎？&lt;br&gt;
不知道的話，可以翻閱前面的&lt;a class="link" href="https://medium.com/@desolution/%E5%BE%9Eleetcode%E5%AD%B8%E6%BC%94%E7%AE%97%E6%B3%95-16-bst-1-41d01e6a9f7a?source=friends_link&amp;amp;sk=c542299d85bd7ffd01a08c64507c47a9" target="_blank" rel="noopener"
&gt;第16篇&lt;/a&gt;的介紹歐！&lt;br&gt;
簡言之，一個合法的BST除了&lt;strong&gt;左邊的節點要全小於根節點，右邊的節點要全大於根節點&lt;/strong&gt; 外，&lt;br&gt;
其&lt;strong&gt;左右子樹也要是BST&lt;/strong&gt; 才行。&lt;br&gt;
觀察n=3的狀況，我們可以將其歸納成3類：&lt;br&gt;
以1為根節點/以2為根節點/以3為根節點。&lt;/p&gt;
&lt;p&gt;首先是1為根節點的狀況：&lt;br&gt;
左邊沒有比其小的節點，故只有一種可能；&lt;br&gt;
右邊有2跟3的組合，相當於n=2的時候的狀況(2種)。&lt;br&gt;
(2跟3等價於1跟2兩個節點會有的組合)&lt;/p&gt;
&lt;p&gt;再來是2為根節點的狀況：&lt;br&gt;
左邊只有1種可能(1這個節點)；&lt;br&gt;
右邊也只有1種可能(3這個節點)。&lt;/p&gt;
&lt;p&gt;最後是3為根節點的狀況：&lt;br&gt;
左邊是1跟2的組合(2種)，&lt;br&gt;
右邊只有1種可能。&lt;/p&gt;
&lt;p&gt;如果我們將n的組合命名為函式f(n)，&lt;br&gt;
那麼顯然f(0)=1(只有一種可能)，f(1)=1。&lt;/p&gt;
&lt;p&gt;計算n=3的組合算法為：&lt;br&gt;
f(0)*f(2) + f(1)*f(1) + f(2)*f(0)&lt;/p&gt;
&lt;p&gt;掌握這個規律的狀態，我們可以得到f(n)的計算方式：&lt;br&gt;
&lt;strong&gt;f(0)*f(n-1) + f(1)*f(n-2) + … + f(n-1)*f(0)&lt;/strong&gt;&lt;br&gt;
那麼，從f(1)開始起算的話，&lt;br&gt;
我們可以一路疊加將f(1)到f(n-1)都算出來，&lt;br&gt;
最後得到我們要的f(n)。&lt;br&gt;
讓f(n)能夠化成f(n-1)或較小的項次的組合，一路化簡到能直接確認的值，&lt;br&gt;
所以這個就是典型的動態規劃的範例。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/ce5c906a7cd1c392881fc66b17bad400.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/73fc12362e96b3eebddf820bc4de0836.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(n²), O(n)&lt;br&gt;
由於計算時兩層迴圈最大都要經歷n，故時間上會和n的平方相關)&lt;/p&gt;
&lt;p&gt;「可以改成&lt;strong&gt;遞迴&lt;/strong&gt; 的方式嗎？」&lt;br&gt;
(可以，我們只要將dp改成字典或HashMap，開一個函式search，&lt;br&gt;
令其在找不到值的時候呼叫自己如 sum += search(i-1) * search(n-i)，&lt;br&gt;
最後也會如同迴圈的解法一樣一路拆解到最底下，&lt;br&gt;
讀者可以自行嘗試看看，實測上兩者速度在實作正確的狀況下，&lt;br&gt;
應該是感受不出太明顯的差異的。)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;/strong&gt;&lt;br&gt;
From Python Taiwan&lt;br&gt;
 曾淯銘: 更正BST的筆誤(連結是對的，本文打錯，是左&amp;lt;根&amp;lt;右，已更正)&lt;br&gt;
 ChenRay Hsieh: 本文的解其實等同於&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E5%8D%A1%E5%A1%94%E5%85%B0%E6%95%B0" target="_blank" rel="noopener"
&gt;Catalan number&lt;/a&gt;，讀者可參考閱讀。&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 24 Dynamic Programming (4)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-24-dynamic-programming-4/</link><pubDate>Mon, 05 Aug 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-24-dynamic-programming-4/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 24 Dynamic Programming (4)" /&gt;&lt;p&gt;&lt;strong&gt;0063. Unique Paths II (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;A robot is located at the top-left corner of a &lt;em&gt;m&lt;/em&gt; x &lt;em&gt;n&lt;/em&gt; grid (marked ‘Start’ in the diagram below).&lt;/p&gt;
&lt;p&gt;The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).&lt;/p&gt;
&lt;p&gt;Now consider if some obstacles are added to the grids. How many unique paths would there be?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-24-dynamic-programming-4/image-001.png"
width="400"
height="183"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-24-dynamic-programming-4/image-001_hu_1ef4767c012293e3.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-24-dynamic-programming-4/image-001_hu_a3224127227bc32a.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="218"
data-flex-basis="524px"
&gt;&lt;/p&gt;
&lt;p&gt;An obstacle and empty space is marked as &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt; respectively in the grid.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;m&lt;/em&gt; and &lt;em&gt;n&lt;/em&gt; will be at most 100.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [0,0,0],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [0,1,0],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [0,0,0]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There is one obstacle in the middle of the 3x3 grid above.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There are two ways to reach the bottom-right corner:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. Right -&amp;gt; Right -&amp;gt; Down -&amp;gt; Down
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. Down -&amp;gt; Down -&amp;gt; Right -&amp;gt; Right
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;這題基本上就是前面Unique Paths I的續集，在棋盤上存在障礙物。&lt;br&gt;
如果我們考慮某個點是障礙物的話，其造成的影響會是什麼呢？&lt;br&gt;
建議讀者可以自行畫幾條路徑試試看，這個狀況下，&lt;br&gt;
會造成的結果為：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;能到達該點的方法數為0(已經是障礙物了)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;承1，因此對1個點來說，&lt;br&gt;
加總的方式應該是&lt;strong&gt;先看這個點是否是障礙物&lt;/strong&gt; ，&lt;br&gt;
不是的話，才需要考慮它&lt;strong&gt;左邊&lt;/strong&gt; 和&lt;strong&gt;上面&lt;/strong&gt; 是否有可以到達的方法數。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我們最開始先檢查輸入的方格是否正常，且第一個如果被擋的話，&lt;br&gt;
代表完全走不出去，直接回傳0即可。扣除掉這個狀況的話，&lt;br&gt;
接著從原點開始的方法數就是&lt;strong&gt;1&lt;/strong&gt; 。接下來便可由此開始進行dp。&lt;/p&gt;
&lt;p&gt;先定義好儲存path的二維陣列並將1放到原點，&lt;br&gt;
依序對每個方格檢查，只要確定它不是障礙物，&lt;br&gt;
就依照判斷將該加上去的部分加上去。&lt;br&gt;
(加到左邊或上面是障礙物的點沒關係，因為它已經是0了)&lt;/p&gt;
&lt;p&gt;全部遍歷過一次以後，回傳右下角的值即可。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/411fc4ae91b90163db883bdce4814478.js"&gt;&lt;/script&gt;
&lt;p&gt;Python的部分要特別留意二維列表的生成，&lt;br&gt;
請勿使用[[0]*n]*m，這樣在第二層會&lt;strong&gt;產生m個指向相同位址的列表&lt;/strong&gt; 。&lt;br&gt;
(第一層不會，因為0的部分還是基本型態而非物件)&lt;br&gt;
(也就是動其中一個row會同步改到其他的row)&lt;br&gt;
我們可以使用二層的List Comprehension來處理，或者第一層用*，&lt;br&gt;
第二層用List Comprehension亦可，這裡示範後者。&lt;br&gt;
(實測上兩者&lt;strong&gt;速度並無明顯差異&lt;/strong&gt; )&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/6dc408a8fad92f997a818d48348b0191.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(m*n), O(m*n)，因我們會遍歷整個二維列表，&lt;br&gt;
且需要另一個二維列表來儲存中間的方法數)&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 21 Dynamic Programming (3)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-21-dynamic-programming-3/</link><pubDate>Mon, 29 Jul 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-21-dynamic-programming-3/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 21 Dynamic Programming (3)" /&gt;&lt;p&gt;&lt;strong&gt;0062. Unique Paths (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;A robot is located at the top-left corner of a &lt;em&gt;m&lt;/em&gt; x &lt;em&gt;n&lt;/em&gt; grid (marked ‘Start’ in the diagram below).&lt;/p&gt;
&lt;p&gt;The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).&lt;/p&gt;
&lt;p&gt;How many possible unique paths are there?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-21-dynamic-programming-3/image-001.png"
width="400"
height="183"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-21-dynamic-programming-3/image-001_hu_1ef4767c012293e3.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-21-dynamic-programming-3/image-001_hu_a3224127227bc32a.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="218"
data-flex-basis="524px"
&gt;&lt;/p&gt;
&lt;p&gt;Above is a 7 x 3 grid. How many possible unique paths are there?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;m&lt;/em&gt; and &lt;em&gt;n&lt;/em&gt; will be at most 100.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: m = 3, n = 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. Right -&amp;gt; Right -&amp;gt; Down
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. Right -&amp;gt; Down -&amp;gt; Right
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. Down -&amp;gt; Right -&amp;gt; Right
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: m = 7, n = 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 28
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;有一個m x n大小的格子，其左上處有一台機器人，每次機器人僅能選擇往右或往下走，目的是要達到右下角的Finish的位置，題目問說當給定m和n時，有多少種不同的方法可以從左上走到右下？&lt;/p&gt;
&lt;p&gt;這題也是典型的動態規劃題目，只要稍稍思考一下，&lt;br&gt;
我們就能發現一件事情：&lt;br&gt;
走到任何一個點的方式，取決於&lt;strong&gt;走到其左的方法數&lt;/strong&gt; 加上&lt;strong&gt;走到其上的方法數&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;那麼，再思考一下走到左邊跟走到上面會有重複的狀況嗎？顯然是不會的。&lt;br&gt;
因為走到一個格子的左邊顯然和走到其上面會相差往下走一格及往右走一格的動作，而且因為機器人也只能往下或往右，所以沒辦法再回頭，故已經走過的部分不可能再繞得回來。&lt;/p&gt;
&lt;p&gt;在這個狀況的特例有幾個：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;機器人所站的&lt;strong&gt;原點&lt;/strong&gt; (按我們的定義一開始就在此，故可以將方法數定為1)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最左邊&lt;/strong&gt; 的一排格子 (僅取決於走到其上面格子的方法數)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最上面&lt;/strong&gt; 的一排格子 (僅取決於走到其左邊格子的方法數)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而實際上從第1點來推算的話，&lt;br&gt;
我們可以知道最左邊一排跟最上面到達的方法數&lt;strong&gt;都會是1&lt;/strong&gt; 。&lt;br&gt;
所以我們可以先將這三點的部分先設定為1，接著從較小的index開始沿途把到達每個點的方法算出來，直到最後將整個grid算完。&lt;/p&gt;
&lt;p&gt;在這個方法下，我們需要一個m x n的陣列用以儲存方法數，為了方便起見，我們就直接叫它dp，讀者亦可命名為grid，&lt;strong&gt;請留意這些命名都只是方便起見，只要你的命名能和面試官溝通即可，我們現在並不是在寫一個大的project，簡短命名並告知你的面試官你的目的是筆者推薦的做法。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最後僅需回傳dp[m-1][n-1]即可。&lt;br&gt;
(註:由於這邊row跟column的交換並不影響結果，&lt;br&gt;
故我們這邊不特別去在意m和n的前後順序。)&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/b513a1c2d12e6d570fd10c00ac971686.js"&gt;&lt;/script&gt;
&lt;p&gt;Python這邊收尾的時候可以用dp[-1][-1]來表示尾端的元素，&lt;br&gt;
宣告的時候則採用list comprehension(列表解析式/列表表達式)。&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/61377205ae47e892c78a4e38dfa68ee2.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(均為O(m*n))&lt;/p&gt;
&lt;p&gt;「空間複雜度是否可以降低？」&lt;br&gt;
(理論上可以，因為實際每次處理的關連部分僅有兩行或兩列，&lt;br&gt;
反覆利用應該可以讓空間需求降低到O(m)或O(n)，但時間複雜度一致)&lt;/p&gt;
&lt;p&gt;「是否有更簡單的解？」&lt;br&gt;
(DP的話，沒有，數學的話，有。&lt;br&gt;
 假設往下叫D，往右叫R，求不同走法的過程，&lt;br&gt;
即相當於在求**(n-1)個D和(m-1)個R的不同排列方法** ，&lt;br&gt;
故答案會是(m-1+n-1)!/(m-1)!(n-1)!，&lt;br&gt;
此時&lt;strong&gt;空間複雜度為O(1)，時間複雜度為O(m+n)&lt;/strong&gt; 。&lt;br&gt;
但階乘的部分當值過大時有可能會有超過int的可能性。)&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 9 Dynamic Programming (2)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-9-dynamic-programming-2/</link><pubDate>Tue, 09 Jul 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-9-dynamic-programming-2/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 9 Dynamic Programming (2)" /&gt;&lt;p&gt;&lt;strong&gt;0070. Climbing Stairs (Easy)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;You are climbing a staircase. It takes &lt;em&gt;n&lt;/em&gt; steps to reach to the top.&lt;/p&gt;
&lt;p&gt;Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Given &lt;em&gt;n&lt;/em&gt; will be a positive integer.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example 1
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: There are two ways to climb to the top.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 1 step + 1 step
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 2 steps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="example-2"&gt;Example 2
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: There are three ways to climb to the top.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. 1 step + 1 step + 1 step
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. 1 step + 2 steps
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. 2 steps + 1 step
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;題目描述有一個要爬n階才能到頂端的階梯，每次只能爬1階或2階，&lt;br&gt;
試求有多少種不同的方法可以走到頂端。&lt;br&gt;
如果以窮舉的話我們可能需要列很久，&lt;br&gt;
所以這時候又回到了看看是否能找出相互關係的時候了。&lt;/p&gt;
&lt;p&gt;我們考慮要爬n階的話，首先要先爬到&lt;strong&gt;n-1&lt;/strong&gt; 階或&lt;strong&gt;n-2&lt;/strong&gt; 階，因為只有一次走1階或一次走2階的選擇。也就是說，走到n階的方法，就相當於&lt;strong&gt;走到n-1階的方法和走到n-2階的方法和&lt;/strong&gt; 。因為最後的步伐已經固定了，我們同時還可以保證&lt;strong&gt;這兩個方法的組合之間不會互相重複&lt;/strong&gt; (一個最後走1步，一個最後走2步)。&lt;/p&gt;
&lt;p&gt;同樣的，走到n-1階的方法=走到(n-2)階的方法+走到(n-3)階的方法，&lt;br&gt;
以此類推拆解，最終我們來到走到第1階的方法跟走到第2階的方法，&lt;br&gt;
分別是1跟2。&lt;/p&gt;
&lt;p&gt;我們可以選擇開一個res的陣列，初始化前2階以後，&lt;br&gt;
一路加上去最終得到到第n階的方法數，下面Java的版本因為陣列由0開始，&lt;br&gt;
有刻意將數字不先行化簡，讀者應該可以很簡單地對照。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/e6ca8d674da9778e3a36362e4c6ec032.js"&gt;&lt;/script&gt;
&lt;p&gt;Python的部分，則採用兩個數s1, s2來輪替使用，可以節省記憶體。&lt;br&gt;
每次應該要做的，是將s1+s2的值擺到s2，而將s2的值擺到s1的位置。&lt;br&gt;
(等於把兩個數代表的位置遞移了一層)&lt;br&gt;
(Java也可以用類似的作法，但需要多宣告一個暫存值進行儲存)&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/36f7e5bd29cd65347e68e9617b6c8b30.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
（O(N), 依方法而定，&lt;br&gt;
上面Java的寫法需要O(N)，Python的寫法則只需O(1)）&lt;/p&gt;
&lt;p&gt;「哪個寫法比較好？」&lt;br&gt;
(以空間節省的角度來說是Python版本的寫法較佳，&lt;br&gt;
但如果我們不止需要算一次的話，執行一次n階，&lt;br&gt;
其實可以將n階以下的走法數量全部記起來，&lt;br&gt;
這樣被讀取的時候可以先查是否可以直接拿結果回傳，&lt;br&gt;
所以反覆執行的效率會變比較好，不過這個就需要再修改一下程式就是了)&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 7 Dynamic Programming (1)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-7-dynamic-programming-1/</link><pubDate>Thu, 04 Jul 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-7-dynamic-programming-1/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 7 Dynamic Programming (1)" /&gt;&lt;p&gt;&lt;strong&gt;0053. Maximum Subarray (Easy)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given an integer array &lt;code&gt;nums&lt;/code&gt;, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input: [-2,1,-3,4,-1,2,1,-5,4],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: 6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Explanation: [4,-1,2,1] has the largest sum = 6.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Follow up:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have figured out the O(&lt;em&gt;n&lt;/em&gt;) solution, try coding another solution using the divide and conquer approach, which is more subtle.&lt;/p&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;題目給定一個整數陣列，要求找到其中一個連續的子陣列，這個子陣列的和是所有子陣列中最大的，並且回傳該總和值。&lt;/p&gt;
&lt;p&gt;這題如果以暴力法來解決的話，我們可以拿到的總連續子陣列數是&lt;br&gt;
N+(N-1)+(N-2)+…+1，每個子陣列中的計算下一組和(如[-2] -&amp;gt; [-2,1])，&lt;br&gt;
都只需一個加法，故時間複雜度會是O(N²)。&lt;/p&gt;
&lt;p&gt;但&amp;hellip;&amp;hellip;感覺很浪費(?)&lt;br&gt;
我們先思考一個問題：&lt;br&gt;
「假設我知道nums中1到i-1的最大子陣列和，&lt;br&gt;
有沒有辦法知道1到i的最大子陣列和呢？」&lt;br&gt;
我們討論1到i的最大子陣列和，應該分兩種情況：&lt;br&gt;
a. &lt;strong&gt;這個子陣列包括index i&lt;/strong&gt;&lt;br&gt;
b. &lt;strong&gt;這個子陣列不包括index i&lt;/strong&gt;&lt;br&gt;
如果是&lt;strong&gt;b&lt;/strong&gt; 的話，那答案其實就是&lt;strong&gt;1到i-1的最大子陣列和&lt;/strong&gt; ；&lt;br&gt;
但如果是&lt;strong&gt;a&lt;/strong&gt; 的話，我們好像還需要一些條件？&lt;br&gt;
什麼條件呢？就是&lt;strong&gt;1到i-1中，包含i-1元素的最大子陣列和&lt;/strong&gt; 。&lt;br&gt;
因為如果是前面所提到的a狀況的話，&lt;br&gt;
那麼1到i的最大連續子陣列，就必須從i-&amp;gt;i-1連回去才行(或乾脆是只有i)。&lt;/p&gt;
&lt;p&gt;所以這麼一來，條件就比較清楚了，我們會需要的有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;到現在為止&lt;strong&gt;包含當前這個元素的最大子陣列和&lt;/strong&gt; ，我們命名為curr(current)&lt;/li&gt;
&lt;li&gt;到目前為止的&lt;strong&gt;最大子陣列和&lt;/strong&gt; ，我們命名為res(result)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;那麼我們就以範例的[-2,1,-3,4,-1,2,1,-5,4]來操作看看。&lt;br&gt;
該怎麼決定curr跟res的初始值呢？因為一開始只有一個值，&lt;br&gt;
所以curr和res應該都等於nums[0]=-2才對。&lt;br&gt;
所以一開始我們將curr和res都設為-2，接下來由i=1開始，&lt;br&gt;
一路往下到最後一個結束。&lt;/p&gt;
&lt;p&gt;i=1: [-2,&lt;em&gt;&lt;strong&gt;1&lt;/strong&gt; *,-3,4,-1,2,1,-5,4]&lt;br&gt;
按我們的定義，curr應該是-2+1和1中較大的值，&lt;br&gt;
我們可以先將curr加上nums[1]，&lt;br&gt;
接下來檢查&lt;/em&gt;&lt;em&gt;curr小於0&lt;/em&gt;* ，或者&lt;strong&gt;curr&amp;lt;nums[1]&lt;/strong&gt; ，&lt;br&gt;
就表示其實我們只要取&lt;strong&gt;nums[1]&lt;/strong&gt; 就好。&lt;br&gt;
(註1: 表示兩者的正負號為**(-, -), (-, +)** ，不論如何&lt;strong&gt;前面那部分貢獻均是負的&lt;/strong&gt; )&lt;br&gt;
(註2: 也可以拆成別的形式或調換順序，但先判斷&amp;lt;0的計算速度會比較快)&lt;br&gt;
(註3: 後面程式碼Java和Python的判斷方式就不同，可自行依喜好決定使用)&lt;br&gt;
所以新的curr為1, 接著再比較得知curr&amp;lt;res，故res也要改為1。&lt;br&gt;
接下來的流程，讀者可以嘗試自己操作一遍再對照一下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i=2: [-2,1,-3,4,-1,2,1,-5,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = 1 + -3 = -2 &amp;lt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = -3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; res = 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i=3: [-2,1,-3,4,-1,2,1,-5,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = -3 + 4 = 1 &amp;lt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; res = 4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i=4: [-2,1,-3,4,-1,2,1,-5,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = 4 + -1 = 3 &amp;gt; -1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i=5: [-2,1,-3,4,-1,2,1,-5,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = 3 + 2 = 5 &amp;gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; res = 5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i=6: [-2,1,-3,4,-1,2,1,-5,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = 5 + 1 = 6 &amp;gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; res = 6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i=7: [-2,1,-3,4,-1,2,1,-5,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = 6 + -5 = 1 &amp;gt; -5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i=8: [-2,1,-3,4,-1,2,1,-5,4]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-&amp;gt; curr = 1 + 4 = 5 &amp;gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;所以最後我們得到res = 6，再回傳即可。&lt;/p&gt;
&lt;p&gt;這個解法第一次並不是很容易上手，而且並非相當直觀的方式，&lt;br&gt;
但它常常可以在特別的地方有效地解決問題。&lt;br&gt;
適用於這類型的解法的問題會有一個特性：&lt;br&gt;
&lt;strong&gt;「N=i+1時的解，通常和N=i時的解以及第i+1的值有關連性」&lt;/strong&gt;&lt;br&gt;
(也有可能跟更前面幾個值同時有關連性)&lt;br&gt;
而我們通常很難直觀地直接用簡單的方式去算出N=i+1的解，&lt;br&gt;
所以會依靠其本身和前面的連動關係，&lt;br&gt;
讓答案像堆積木一樣，從i=0開始堆到最後面得到最終的答案。&lt;/p&gt;
&lt;p&gt;有些問題可能未必是一層一層疊上去，&lt;br&gt;
也有可能是把一個大問題拆成數個小問題，&lt;br&gt;
最後將其組合起來得到大問題的答案。&lt;br&gt;
但通常我們最常見的形式還是如上面那樣子按順序堆疊的。&lt;/p&gt;
&lt;p&gt;上面這樣子形式的解題方法，&lt;br&gt;
被稱之為&lt;strong&gt;動態規劃(Dynamic Programming)&lt;/strong&gt; ，或者也常簡稱為DP。&lt;br&gt;
每個動態規劃的問題都會有些不一樣，&lt;br&gt;
但只要抓到其中的連動性，找到從&lt;strong&gt;i -&amp;gt; i+1&lt;/strong&gt; 中間的關聯，&lt;br&gt;
就可以順利解開題目。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/7847030300839993b7b6f7cbf723ded2.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/37fa93e5c41056d82306906bee93ad2d.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(N), O(1))&lt;/p&gt;
&lt;p&gt;「如果不使用DP是否有O(N)解？」&lt;br&gt;
(可以使用分治法，請參見 &lt;a class="link" href="https://leetcode.com/problems/maximum-subarray/discuss/20372/How-to-solve-%22Maximum-Subarray%22-by-using-the-divide-and-conquer-approach" target="_blank" rel="noopener"
&gt;*&lt;strong&gt;LeetCode這篇討論&lt;/strong&gt; *&lt;/a&gt;底下的回應)&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item></channel></rss>