<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>BST on 跟著 Desolve 學程式</title><link>https://desolve.pages.dev/tags/bst/</link><description>Recent content in BST on 跟著 Desolve 學程式</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><lastBuildDate>Tue, 09 Jun 2020 00:00:00 +0800</lastBuildDate><atom:link href="https://desolve.pages.dev/tags/bst/index.xml" rel="self" type="application/rss+xml"/><item><title>從LeetCode學演算法 - 96 BST (5) / DFS (10)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-96-bst-5-dfs-10/</link><pubDate>Tue, 09 Jun 2020 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-96-bst-5-dfs-10/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 96 BST (5) / DFS (10)" /&gt;&lt;p&gt;&lt;strong&gt;1008. Construct Binary Search Tree from Preorder Traversal (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="寫在前面"&gt;寫在前面
&lt;/h2&gt;&lt;p&gt;容筆者工商一下，&lt;br&gt;
&lt;strong&gt;「從Leetcode學演算法｜進階篇」在今天(6/9)中午12點&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://hiskio.com/packages/YoRY45yZm" target="_blank" rel="noopener"
&gt;https://hiskio.com/packages/YoRY45yZm&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://hiskio.com/packages/MByQ4pw3W" target="_blank" rel="noopener"
&gt;https://hiskio.com/packages/MByQ4pw3W&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;另外，&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Return the root node of a binary &lt;strong&gt;search&lt;/strong&gt; tree that matches the given &lt;code&gt;preorder&lt;/code&gt; traversal.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Recall that a binary search tree is a binary tree where for every node, any descendant of&lt;/em&gt; &lt;code&gt;node.left&lt;/code&gt; &lt;em&gt;has a value&lt;/em&gt; &lt;code&gt;&amp;lt;``node.val&lt;/code&gt;&lt;em&gt;, and any descendant of&lt;/em&gt; &lt;code&gt;node.right&lt;/code&gt; &lt;em&gt;has a value&lt;/em&gt; &lt;code&gt;&amp;gt;``node.val&lt;/code&gt;&lt;em&gt;. Also recall that a preorder traversal displays the value of the&lt;/em&gt; &lt;code&gt;node&lt;/code&gt; &lt;em&gt;first, then traverses&lt;/em&gt; &lt;code&gt;node.left&lt;/code&gt;&lt;em&gt;, then traverses&lt;/em&gt; &lt;code&gt;node.right&lt;/code&gt;&lt;em&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It’s guaranteed that for the given test cases there is always possible to find a binary search tree with the given requirements.&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: [8,5,1,7,10,12]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: [8,5,10,1,7,null,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;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-96-bst-5-dfs-10/0_onS6QbVL4p9hvos1.png"
width="590"
height="386"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-96-bst-5-dfs-10/0_onS6QbVL4p9hvos1_hu_7d02e4500993eee8.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-96-bst-5-dfs-10/0_onS6QbVL4p9hvos1_hu_15ef9a45075a191d.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="152"
data-flex-basis="366px"
&gt;&lt;/p&gt;
&lt;h3 id="constraints"&gt;Constraints
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= preorder.length &amp;lt;= 100&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= preorder[i] &amp;lt;= 10^8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The values of &lt;code&gt;preorder&lt;/code&gt; are distinct.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;從給定的&lt;strong&gt;前序走訪&lt;/strong&gt; 一棵二元搜尋樹的結果，&lt;br&gt;
重建一棵符合的二元搜尋樹，並回傳其根節點。&lt;br&gt;
題目給出的測試資料均保證可以找到一個符合的二元搜尋樹。&lt;/p&gt;
&lt;p&gt;我們很早以前已經解說過&lt;strong&gt;二元搜尋樹的特性&lt;/strong&gt; 了，&lt;br&gt;
&lt;strong&gt;前序走訪(preorder)&lt;/strong&gt; 表示順序是&lt;strong&gt;根-左-右&lt;/strong&gt; ，&lt;br&gt;
不像是&lt;strong&gt;中序走訪(inorder)&lt;/strong&gt; 會剛好是&lt;strong&gt;左-根-右，順序會剛好由小到大排列&lt;/strong&gt; 。&lt;br&gt;
那麼，我們要怎麼樣才能架構一個合理的BST(二元搜尋樹)呢？&lt;br&gt;
由於BST和preorder的特性，當我們一路往左走的時候，&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;/p&gt;
&lt;p&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;strong&gt;小&lt;/strong&gt; ，代表它是被包含在當下這個子二元樹，&lt;br&gt;
反之，則代表它應該&lt;strong&gt;在上一層或更上層&lt;/strong&gt; 才對。&lt;br&gt;
此外，我們可以設定一個class的變數i，&lt;br&gt;
用來紀錄現在我們建立二元樹的過程走到哪個index。&lt;/p&gt;
&lt;p&gt;那麼我們來整理一下流程：&lt;br&gt;
0. 初始化一個class變數 &lt;strong&gt;i = 0&lt;/strong&gt; 。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先檢查當前的陣列/串列是不是&lt;strong&gt;沒東西&lt;/strong&gt; ，沒東西的話就回傳null/None。&lt;/li&gt;
&lt;li&gt;將&lt;strong&gt;int的最大值&lt;/strong&gt; 作為&lt;strong&gt;邊界值&lt;/strong&gt; bound，&lt;br&gt;
傳入用來建立二元樹的函式(這裡命名為&lt;strong&gt;build&lt;/strong&gt; )&lt;/li&gt;
&lt;li&gt;在build函式中，檢查如果&lt;strong&gt;i走完全長了&lt;/strong&gt; 或者&lt;strong&gt;preorder[i] &amp;gt; bound，&lt;br&gt;
前者表示整個樹重建完了，後者表示這個子樹底下對於preorder[i]來說不可能放在任何一個地方了，所以回傳null/None回到上一層。&lt;strong&gt;4. 在這層建立一個&lt;/strong&gt; 根節點root&lt;/strong&gt;，** 其值為preorder[i]&lt;strong&gt;，完成後&lt;/strong&gt; 將i遞增**。&lt;/li&gt;
&lt;li&gt;接下來要建立root.left，呼叫build函式，&lt;br&gt;
將preorder&lt;strong&gt;及邊界值root.val&lt;/strong&gt; 傳入。&lt;br&gt;
(因為root的左子樹所有值都要小於root的值)&lt;/li&gt;
&lt;li&gt;再來建立root.right，呼叫build函式，&lt;br&gt;
將preorder及邊界值bound傳入。&lt;br&gt;
(因為root的右子樹裡的所有值要介於&lt;strong&gt;root的值&lt;/strong&gt; 和&lt;strong&gt;上一層限制的bound&lt;/strong&gt; 之間)&lt;/li&gt;
&lt;li&gt;這層等於建立完畢了，&lt;strong&gt;將root回傳&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我們簡單拿Example 1為範例來嘗試推導看看：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (0, 8, Integer.MAX_VALUE)&lt;br&gt;
=&amp;gt; root節點建立，其值為8，i遞增，呼叫build(preorder, 8)以建立左節點。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (1, 5, 8)&lt;br&gt;
=&amp;gt; 建立根節點，其值為5，i遞增，呼叫build(preorder, 5)以建立左節點。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (2, 1, 5)&lt;br&gt;
=&amp;gt; 建立根節點，其值為1，i遞增，呼叫build(preorder, 1)以建立左節點。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (3, 7, 1)&lt;br&gt;
=&amp;gt; 7&amp;gt;1，所以表示這層沒辦法放了，回傳null到上一層。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (3, 7, 5)&lt;br&gt;
=&amp;gt; 走到root.right這行，呼叫build(preorder, 8)以建立右節點。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (3, 7, 8)&lt;br&gt;
=&amp;gt; 建立根節點，其值為7，i遞增，&lt;br&gt;
呼叫root.left及root.right兩行都會回傳null，&lt;br&gt;
所以回傳該節點到上一層。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (4, 10, 8)&lt;br&gt;
=&amp;gt; 在5的底下建立完7的右節點了，這邊也完成了，&lt;br&gt;
回傳5的節點回到上一層。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (4, 10, Integer.MAX_VALUE)&lt;br&gt;
=&amp;gt; 走到root.right這行，呼叫build(preorder, Integer.MAX_VALUE)。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (4, 10, Integer.MAX_VALUE)&lt;br&gt;
=&amp;gt; 建立根節點，其值為10，i遞增，&lt;br&gt;
root.left這行會回傳null，&lt;br&gt;
root.right傳入build(preorder, Integer.MAX_VALUE)。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(i, preorder[i], bound) = (5, 12, Integer.MAX_VALUE)&lt;br&gt;
=&amp;gt; 建立根節點，其值為12，i遞增。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;後面的部分由於i已經到達6，所以會往上層回到8的這層，&lt;br&gt;
最後回傳根節點(值為8)，結束。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;請讀者嘗試在紙上畫出來推過一遍，有助於更了解整個程式運行。&lt;br&gt;
由於我們是先一路往左深入並建立節點，碰到無法建立時，&lt;br&gt;
才回到上一層並嘗試往右走，&lt;br&gt;
所以這樣子的方式是&lt;strong&gt;DFS(深度優先搜尋)&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;
使用int時可以用Integer.MAX_VALUE作為初始邊界(即int能表示的最大值)。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/39b4b56e6af4cda414fbe3fdc93fa9a3.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分，我們可以設定bound在未傳入值時預設值當作&lt;strong&gt;float(&amp;lsquo;inf&amp;rsquo;)&lt;/strong&gt; ，&lt;br&gt;
即可使用同一個函式進行遞迴。&lt;br&gt;
此外，還是不要忘記Python並沒有++或&amp;ndash;，請自己換成用**”self.i += 1&amp;quot;** 。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/751f9e2e2f88ba60f6d45a2708341330.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(O(length of array)/O(1), 如果計算call stack的話則是O(BST的深度))&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;另外，「從Leetcode學演算法｜基礎篇」已經回原價囉，&lt;br&gt;
先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，&lt;br&gt;
雖然整捆一起買總體比較划算(差290而已就有整組了阿XD)，&lt;br&gt;
如果你還是想先試試基礎課的話，&lt;br&gt;
&lt;strong&gt;300元折抵的連結&lt;/strong&gt; 在這邊： &lt;a class="link" href="https://hiskio.com/courses/319?promo_code=NEXLJXE" target="_blank" rel="noopener"
&gt;https://hiskio.com/courses/319?promo_code=NEXLJXE&lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 51 BST (4)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-51-bst-4/</link><pubDate>Tue, 17 Sep 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-51-bst-4/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 51 BST (4)" /&gt;&lt;p&gt;&lt;strong&gt;0235. Lowest Common Ancestor of a Binary Search Tree (Easy)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(當然，Medium的拍手也可以多拍幾下啦XD)&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.&lt;/p&gt;
&lt;p&gt;According to the &lt;a class="link" href="https://en.wikipedia.org/wiki/Lowest_common_ancestor" target="_blank" rel="noopener"
&gt;definition of LCA on Wikipedia&lt;/a&gt;: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow &lt;strong&gt;a node to be a descendant of itself&lt;/strong&gt; ).”&lt;/p&gt;
&lt;p&gt;Given binary search tree: root = [6,2,8,0,4,7,9,null,null,3,5]&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/image-001.png"
loading="lazy"
&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;/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: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
&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: The LCA of nodes 2 and 8 is 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="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: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
&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: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
&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;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All of the nodes’ values will be unique.&lt;/li&gt;
&lt;li&gt;p and q are different and both values will exist in the BST.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;給定一個二元搜尋樹及其中兩個不同的節點，&lt;br&gt;
試找出它們的最近共同祖先(LCA)。&lt;/p&gt;
&lt;p&gt;題目有標註說一個節點可以視作自己的後裔(descendant)，&lt;br&gt;
這點會有影響，還請留意。&lt;/p&gt;
&lt;p&gt;那麼，我們如何尋找這個最近共同祖先呢？&lt;br&gt;
首先要知道，這是一棵二元搜尋樹，假設這個LCA的節點叫作L好了，&lt;br&gt;
兩個節點分別叫p跟q，那麼我們可以考慮以下幾個狀況：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果L&lt;strong&gt;是p或q其中之一&lt;/strong&gt; 的話，&lt;strong&gt;先遇到誰，就代表誰是那個LCA&lt;/strong&gt; 。&lt;br&gt;
(因為先遇到的節點會是後面的那個節點的祖先)&lt;/li&gt;
&lt;li&gt;如果&lt;strong&gt;L不是p或q其中之一&lt;/strong&gt; 的話，&lt;strong&gt;L的値的範圍必在p.val和q.val之間&lt;/strong&gt; ，&lt;br&gt;
也就是說兩者會位在L的不同側的子樹。&lt;br&gt;
(即p.val &amp;lt; L.val &amp;lt; q.val或p.val &amp;gt; L.val &amp;gt; q.val)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果從root開始判斷的話，就可以分成幾種情況：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;root的値和p或q的值相等&lt;/strong&gt; =&amp;gt; ** 直接回傳root** (p或q就是L)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;root的値在p和q的值的範圍之內&lt;/strong&gt; =&amp;gt; ** 直接回傳root**&lt;br&gt;
(即&lt;strong&gt;p.val &amp;lt; L.val &amp;lt; q.val&lt;/strong&gt; 或&lt;strong&gt;p.val &amp;gt; L.val &amp;gt; q.val&lt;/strong&gt; )&lt;/li&gt;
&lt;li&gt;p和q的値都&lt;strong&gt;小於&lt;/strong&gt; root的值 =&amp;gt; 往下找&lt;strong&gt;root.left&lt;/strong&gt; 的狀況遞迴&lt;/li&gt;
&lt;li&gt;p和q的値都&lt;strong&gt;大於&lt;/strong&gt; root的值 =&amp;gt; 往下找&lt;strong&gt;root.right&lt;/strong&gt; 的狀況遞迴&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;也就是說，最終總會找到&lt;strong&gt;L是p或q之一&lt;/strong&gt; ，或者&lt;strong&gt;L能將兩個節點拆成兩邊&lt;/strong&gt; 。&lt;br&gt;
於是我們可以輕鬆解出這個題目，在Python的部分，&lt;br&gt;
除了要留意a &amp;lt; b &amp;lt; c這種形式是Python才能用的，Java不接受以外，&lt;br&gt;
這邊在Java的解答中要提供一個較簡潔的解法。&lt;/p&gt;
&lt;p&gt;仔細思考的話，我們可以發現1, 2其實可以看作一件事情：&lt;br&gt;
root.val - p.val和root.val - q.val的關係。&lt;br&gt;
當符合&lt;strong&gt;1.&lt;/strong&gt; 的時候，上面的兩個式子&lt;strong&gt;會有一個等於0&lt;/strong&gt; ；&lt;br&gt;
當符合&lt;strong&gt;2.&lt;/strong&gt; 的時候，上面的兩個式子&lt;strong&gt;會一正一負&lt;/strong&gt; 。&lt;br&gt;
所以&lt;strong&gt;兩者相乘&lt;/strong&gt; 時，符合1.跟2.的條件的狀況下，&lt;br&gt;
&lt;strong&gt;結果會&amp;lt;=0 (或&amp;lt;1，因為值是int)。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同時，當不符1.且不符2.時，&lt;strong&gt;由於p, q已經確定是同邊&lt;/strong&gt; 了，&lt;br&gt;
只需要拿p來比較即可，不用再去比較q。&lt;/p&gt;
&lt;p&gt;根據上面的推導我們可以寫成Java的答案版本。&lt;br&gt;
同時，由於每次遞迴都只有動到root所指向的節點，&lt;br&gt;
所以我們也可以很簡單地將其改動成迭代的解法，&lt;br&gt;
由於不需call stack，總體速度有可能會有些許的加快。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/106c3e2be26fd82442e842490f20a1e6.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/40c2247b1ea27812df45271cb20aa9f9.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(Worst case: O(N)/O(N) (如果節點都在同一邊)&lt;br&gt;
平衡樹的話最大會走到整個深度的節點，是O(logN))&lt;br&gt;
(用迭代解的話，因為不用call stack，空間複雜度為O(1))&lt;/p&gt;
&lt;p&gt;「用相乘的方法會有什麼副作用？」&lt;br&gt;
(在有限定變數是int的狀況下，&lt;strong&gt;相乘有機會導致溢位&lt;/strong&gt; ，所以如果這題的測試資料刁鑽一點的話，請不要用相乘的，一組一組判斷就好。)&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;1.&lt;a class="link" href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0236. Lowest Common Ancestor of a Binary Tree&lt;/strong&gt; &lt;/a&gt;(如果這棵樹只是&lt;strong&gt;二元樹&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學演算法 - 35 BST (3)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-35-bst-3/</link><pubDate>Tue, 20 Aug 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-35-bst-3/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 35 BST (3)" /&gt;&lt;p&gt;&lt;strong&gt;0108. Convert Sorted Array to Binary Search Tree (Easy)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given an array where elements are sorted in ascending order, convert it to a height balanced BST.&lt;/p&gt;
&lt;p&gt;For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of &lt;em&gt;every&lt;/em&gt; node never differs by more than 1.&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;/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;Given the sorted array: [-10,-3,0,5,9],
&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;/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;One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:
&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; 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; -3 9
&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; -10 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;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;給定一個陣列，其元素以&lt;strong&gt;升冪排序&lt;/strong&gt; (也就是後面的一定比前面大)，&lt;br&gt;
試將其轉成一個高度平衡的二元搜尋樹。&lt;/p&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-20-tree-6-e08dedd83656?source=friends_link&amp;amp;sk=8b1b089b81ea49c4572d84f8103427b4" target="_blank" rel="noopener"
&gt;0110. Balanced Binary Tree&lt;/a&gt;)，&lt;br&gt;
這邊就不再贅述，簡言之就是對每個節點，&lt;br&gt;
其兩邊的子樹深度相差均&amp;lt;=1就對了！&lt;/p&gt;
&lt;p&gt;我們知道要達到這個條件，最基本的就是一個root的左右兩邊要公平，&lt;br&gt;
所以最簡單的作法就是取中位數作為根，其左邊就是左子樹的所有節點，&lt;br&gt;
右邊就是右子樹的所有節點；再分別讓各自的左右子樹再次拆分，直到分到沒有節點為止。&lt;/p&gt;
&lt;p&gt;這樣作可以讓每一層都均分節點，從而讓每個分支的深度基本接近一致。&lt;br&gt;
故整體流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;檢查陣列是否是空的或者null，是的話直接回傳&lt;/li&gt;
&lt;li&gt;呼叫一個用來遞迴建立BST的函式，這邊命名成getNode()&lt;/li&gt;
&lt;li&gt;getNode會輸入陣列以及當下的左右邊界(nums, l, r) &lt;br&gt;
(一開始l = 0, r = N-1, N是nums的總數)&lt;/li&gt;
&lt;li&gt;每次先檢查左右邊界是否黃金交叉(表示已經完成了，可以回傳null)&lt;/li&gt;
&lt;li&gt;讓mid = l加r的一半，直接建立一個root節點&lt;/li&gt;
&lt;li&gt;root節點的&lt;strong&gt;左節點&lt;/strong&gt; 就應該是呼叫&lt;strong&gt;getNode(nums, l, mid-1)&lt;/strong&gt; 得到的結果&lt;/li&gt;
&lt;li&gt;root節點的&lt;strong&gt;右節點&lt;/strong&gt; 則會是&lt;strong&gt;getNode(nums, mid+1, r)&lt;/strong&gt; 得到的結果&lt;/li&gt;
&lt;li&gt;回傳root&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我們可以看到每次會抓中間值產生一個節點，再利用已排序的特性，&lt;br&gt;
繼續進入遞迴往下將左邊和右邊的節點處理完畢。&lt;br&gt;
思考它的執行流程，應該會發現總體而言我們會先一路來到最左邊的節點，&lt;br&gt;
再回頭建立每個遞迴函式的右邊節點；&lt;br&gt;
也就是說，程式執行的優先順序是&lt;strong&gt;先往深處的方向走&lt;/strong&gt; 而非先將這一層的狀況處理完，這種模式我們稱之為&lt;strong&gt;深度優先搜尋(Depth-First Search, DFS)&lt;/strong&gt; ；&lt;br&gt;
如果換作是優先順序是&lt;strong&gt;先廣泛地處理完這一層，再往下一層走&lt;/strong&gt; ，這種模式就稱之為&lt;strong&gt;廣度優先搜尋(Breadth-First Search, BFS)&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;程式碼的部分，僅需留意Java因為想避免overflow的狀況，&lt;br&gt;
計算的方式為 &lt;strong&gt;start + (end - start) / 2&lt;/strong&gt; ，而非(start + end) / 2。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/e2c3d6cc2abcaafed409efcbdcd2be63.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/595347ffa074df96a6a00bd276ae19ec.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;
每個節點都會掃過一遍，且基本和其他節點沒有太多連帶關係。)&lt;/p&gt;
&lt;p&gt;「那麼如果要將一個BST轉成&lt;strong&gt;排序陣列&lt;/strong&gt; 呢？」&lt;br&gt;
(原則上可用&lt;strong&gt;Inorder Traversal&lt;/strong&gt; ，&lt;br&gt;
但留意不加NIL的狀況其實中間樹的架構資訊可能會就此流失掉)&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/convert-sorted-list-to-binary-search-tree/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0109. Convert Sorted List to Binary Search Tree&lt;/strong&gt; &lt;/a&gt;&lt;strong&gt;(起始給的從陣列/串列改成排序好的LinkedList)&lt;/strong&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學演算法 - 32 BST (2)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-32-bst-2/</link><pubDate>Fri, 16 Aug 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-32-bst-2/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 32 BST (2)" /&gt;&lt;p&gt;&lt;strong&gt;0700. Search in a Binary Search Tree (Easy)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given the root node of a binary search tree (BST) and a value. You need to find the node in the BST that the node’s value equals the given value. Return the subtree rooted with that node. If such node doesn’t exist, you should return NULL.&lt;/p&gt;
&lt;p&gt;For example,&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;/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;Given the tree:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 4
&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 7
&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; 1 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;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;/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;And the value to search: 2
&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;You should return this subtree:&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; 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; 1 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;p&gt;In the example above, if we want to search the value &lt;code&gt;5&lt;/code&gt;, since there is no node with value &lt;code&gt;5&lt;/code&gt;, we should return &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that an empty tree is represented by &lt;code&gt;NULL&lt;/code&gt;, therefore you would see the expected output (serialized tree format) as &lt;code&gt;[]&lt;/code&gt;, not &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;給定一個二元搜尋樹及一個值，試找到這個樹上含有該值的節點；&lt;br&gt;
如果找不到任何節點的值和此值相等的話，回傳NULL。&lt;/p&gt;
&lt;p&gt;一個Binary Search Tree在進行搜尋特定值上最大的好處就是，&lt;br&gt;
**碰到相等是目標，比完較小往左走，&lt;br&gt;
比完較大往右走，走到盡頭就沒有。(XDDDD)**類似binary search，只是我們的每次切半/改動上下界的操作，&lt;br&gt;
更改為往左走或往右走。&lt;/p&gt;
&lt;p&gt;所以我們只要進行遞迴，直到走到NULL(NIL)或走到剛好對的值即可，&lt;br&gt;
下面的程式碼中，由於判斷&lt;strong&gt;root是否為NIL&lt;/strong&gt; 及&lt;strong&gt;root的值等於目標值&lt;/strong&gt; 的狀況，&lt;br&gt;
均為&lt;strong&gt;回傳root&lt;/strong&gt; (雖然一種情況是NIL，另一種情況不是)，&lt;br&gt;
所以我們可以將之合併。&lt;/p&gt;
&lt;p&gt;而當&lt;strong&gt;val &amp;lt; root.val&lt;/strong&gt; 的時候，&lt;br&gt;
選擇&lt;strong&gt;往左走&lt;/strong&gt; 去找比當下的root&lt;strong&gt;更小的值&lt;/strong&gt; 來比較，反之則往右走。&lt;/p&gt;
&lt;p&gt;在實測上以筆者目前的觀察，是否全數使用if/elif連貫的判斷式，&lt;br&gt;
或者前面root的回傳是否合併成一個情況，&lt;br&gt;
均&lt;strong&gt;對執行的速度沒有特別明顯的影響&lt;/strong&gt; ，&lt;br&gt;
故讀者可依自己的喜好選擇撰寫的方式，只需邏輯正確即可。&lt;/p&gt;
&lt;p&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/0e78b4ea04bb300bf519848a8bd0121f.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/c3a2e316115c9a128256dfd3a76a1b5c.js"&gt;&lt;/script&gt;
&lt;p&gt;如果讀者習慣於使用LeetCode解二元樹或二元搜尋樹的題目，&lt;br&gt;
應該會發現其實&lt;strong&gt;二元搜尋樹是可以使用陣列/串列的方式進行輸入&lt;/strong&gt; 的。&lt;br&gt;
這麼做的好處是只要管理好index，就可以用&lt;strong&gt;index的操作&lt;/strong&gt; 來達到走訪某個節點的目的，而不用真的去把每個節點都進行連結到left/right。&lt;br&gt;
缺點的部分則是有些地方必須輸入null進去(因為有可能會是null節點)。&lt;/p&gt;
&lt;p&gt;讀者可以找一些題目來思考一下，&lt;br&gt;
(像是前面的&lt;a class="link" href="https://leetcode.com/problems/binary-tree-inorder-traversal/" target="_blank" rel="noopener"
&gt;0094. Binary Tree Inorder Traversal&lt;/a&gt;)&lt;br&gt;
如果從index i想要走到其left/right節點，這兩個的節點index會是多少呢？&lt;br&gt;
讀者可以開啟Testcase中的Tree Visualizer，&lt;br&gt;
來觀看輸入的陣列會長成的樹的形狀。&lt;br&gt;
(註：這種表示法未必是通用的，但可以做為參考。)&lt;/p&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
(&lt;strong&gt;Worst case O(N)/Average Case O(logN)&lt;/strong&gt; , O(1)，&lt;br&gt;
最糟的狀況是所有節點集中在同一側，一路搜尋到最底下；&lt;br&gt;
平均來說，如果節點較接近平衡的分布的話，&lt;br&gt;
每次搜尋往下走能去掉一半的可能性，所以會是O(logN)。&lt;br&gt;
由於不需要額外的紀錄，所以空間複雜度為O(1))&lt;/p&gt;
&lt;h2 id="相似及延伸"&gt;相似及延伸
&lt;/h2&gt;&lt;p&gt;1.&lt;a class="link" href="https://leetcode.com/problems/insert-into-a-binary-search-tree/" target="_blank" rel="noopener"
&gt;&lt;strong&gt;0701. Insert into a Binary Search Tree&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks suggestions/corrections from viewers:&lt;/strong&gt; 感謝&lt;strong&gt;Tony Kuo&lt;/strong&gt; 的建議，這邊附上之前講的BST定義及validation的文章。&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;&lt;strong&gt;從LeetCode學演算法 — 16 BST (1)&lt;/strong&gt; &lt;/a&gt; &lt;strong&gt;(0098. Validate Binary Search Tree)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(歡迎提供意見協助更正歐~)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 16 BST (1)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/</link><pubDate>Sun, 21 Jul 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 16 BST (1)" /&gt;&lt;p&gt;&lt;strong&gt;0098. Validate Binary Search Tree (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given a binary tree, determine if it is a valid binary search tree (BST).&lt;/p&gt;
&lt;p&gt;Assume a BST is defined as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The left subtree of a node contains only nodes with keys &lt;strong&gt;less than&lt;/strong&gt; the node’s key.&lt;/li&gt;
&lt;li&gt;The right subtree of a node contains only nodes with keys &lt;strong&gt;greater than&lt;/strong&gt; the node’s key.&lt;/li&gt;
&lt;li&gt;Both the left and right subtrees must also be binary search trees.&lt;/li&gt;
&lt;/ul&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; 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; 1 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;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: [2,1,3]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: true
&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; 5
&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; 1 4
&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 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;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: [5,1,4,null,null,3,6]
&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: The root node&amp;#39;s value is 5 but its right child&amp;#39;s value is 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;題目給定一個二元樹，檢查它是否是二元搜尋樹(Binary Search Tree)。&lt;br&gt;
終於我們來到二元樹的進階版了！&lt;br&gt;
二元搜尋樹如同題目說明，要符合以下三個特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;任一個節點的&lt;strong&gt;左子樹的所有節點值&lt;/strong&gt; 均&lt;strong&gt;小於&lt;/strong&gt; 該節點自身的值&lt;/li&gt;
&lt;li&gt;任一個節點的&lt;strong&gt;右子樹的所有節點值&lt;/strong&gt; 均&lt;strong&gt;大於&lt;/strong&gt; 該節點自身的值&lt;/li&gt;
&lt;li&gt;二元搜尋樹的&lt;strong&gt;左子樹&lt;/strong&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;
反之往右邊走的時候，要比自己大。也因為這個特性，當這棵樹足夠平衡時(節點分布的很均勻時)，會相當有利於&lt;strong&gt;搜尋值，因為每次都幾乎可以排除掉一半的可能性&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-001.png"
width="664"
height="381"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-001_hu_575e8918d358955e.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-001_hu_816c519ca3695ad9.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="174"
data-flex-basis="418px"
&gt;&lt;/p&gt;
&lt;p&gt;Binary Serach Tree (Balanced, Complete, Perfect)&lt;/p&gt;
&lt;p&gt;以下面的圖來說，我們想要從一個有15個節點的二元搜尋樹找到58這個值，&lt;br&gt;
就要從根節點開始，每次比較大小，&lt;strong&gt;若58比較大就往右邊走，比較小就往左邊走，直到找到剛好的值，或是碰到NIL(沒有別的節點可以搜尋)為止&lt;/strong&gt; 。&lt;br&gt;
可以看到圖中由於&lt;strong&gt;深度一樣&lt;/strong&gt; 的關係，不論搜尋什麼值，我們可以預期最多就只需要&lt;strong&gt;4次&lt;/strong&gt; 的比對就可以找出任意一個值是否在這棵樹裡面；&lt;strong&gt;每次刪去一半的可能性&lt;/strong&gt; ，所以如果總節點有N個的話，搜尋的複雜度最高即為&lt;strong&gt;O(logN)&lt;/strong&gt; 。&lt;br&gt;
(記得我們提過二元樹不一定非得要全部都有連接節點，這個結果是建立在這棵二元搜尋樹是&lt;strong&gt;平衡(balanced)&lt;/strong&gt; 的狀況，如果這棵樹全部都改成只有左邊的節點的話，結果可是會變成O(N)的！)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-002.gif"
width="684"
height="438"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-002_hu_f03af607b77b9645.gif 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-002_hu_fa3d7cb4710153db.gif 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="156"
data-flex-basis="374px"
&gt;&lt;/p&gt;
&lt;p&gt;Binary Search for value 58&lt;/p&gt;
&lt;p&gt;我們同樣以上面這棵樹為例，&lt;br&gt;
如果我們想知道它從小到大的節點怎麼排序呢？&lt;br&gt;
這裡就需要使用到In-order Traversal了。&lt;br&gt;
In-order的順序為左-中-右，代表每次我們目標要先拿到左邊的值，接著是中間，最後才是右邊的值；我們最後希望拿到的是[18, 20, 22, 33, 36, 37, 38, 43, 52, 54, 58, 61, 63, 66, 68]的話，我們要先一路走到&lt;strong&gt;最左邊&lt;/strong&gt; 的節點，代表&lt;strong&gt;左邊沒有更小的值&lt;/strong&gt; 了，才能將其印出來(18)，接著第二小的值則是最左邊節點的父節點(20)，而對33來說，還有20的右節點22比它還要小，最後以此類推，每次找到下一個最小值。&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;/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;inorder(root) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if root == NIL return
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inorder(root.left)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(root.val)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inorder(root.right)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;br&gt;
相信會較為理解這整個流程。留意上面由於當發現NIL的時候就直接return回到了遞迴的上一層，所以就會造成類似&lt;strong&gt;往上走一層&lt;/strong&gt; 的效果。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-003.gif"
width="685"
height="586"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-003_hu_aac564f6538dac48.gif 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-16-bst-1/image-003_hu_9129d59aa64eb58e.gif 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="116"
data-flex-basis="280px"
&gt;&lt;/p&gt;
&lt;p&gt;In-order Traversal&lt;/p&gt;
&lt;p&gt;回到我們的題目，我們已經知道在In-order的狀況下，對於二元搜尋樹可以得到一個由小到大的順序，所以只要記住上一個節點，每次去比較上一個節點和現在走到的節點，當現在的節點跟上一個節點相比較小或相等時，表示這不是二元搜尋樹(因為越後面的節點必須較大才行)；反之，當每個節點都走完沒有錯誤時，這時候就可以確認這個二元樹是二元搜尋樹了。&lt;/p&gt;
&lt;p&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;/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;let last = NIL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;isValidBST(root) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if root == NIL return true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if !isValidBST(root.left) return false
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if last != NIL and root.val &amp;lt;= last.val return false
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; last = root // 更新上一個節點的位置
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return isValidBST(root.right)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&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;Java的寫法部分，我們可以宣告一個class的變數last，&lt;br&gt;
用來存放上一個走到的節點(放在函式內部的話會被洗掉)&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/4071ba0ef72ce57f097892815c7ae4c5.js"&gt;&lt;/script&gt;
&lt;p&gt;Python的部分，請留意到記得在呼叫時使用self的關鍵字，&lt;br&gt;
否則可能會無法在isValidBST中取得last。&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/dcfa3b0ff6d68195c8129de4f73a83fa.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
（O(N), O(1)，因為要走過整個BST，&lt;br&gt;
但除了幾個變數外，不需額外的資料結構）&lt;/p&gt;
&lt;p&gt;「可否不用遞迴呢？」&lt;br&gt;
(可以，使用Stack，可以用迴圈讓每次先將root塞入，一路向左邊走將每個左節點放入Stack中，接下來同樣每次取出一個節點，判斷和前一個的大小比較。最後每個左側處理完以後，再將位置移向右節點，迴圈重複即可。)&lt;/p&gt;
&lt;p&gt;「可以不用class的變數來解此題嗎？」&lt;br&gt;
(可以，有一種解法是記錄對某個節點的&lt;strong&gt;最小值和最大值限制&lt;/strong&gt; ，將遞迴函式增加為傳入&lt;strong&gt;root, min, max&lt;/strong&gt; 並隨著每次看到的節點&lt;strong&gt;更新&lt;/strong&gt; 其底下的限制條件，這樣就不需要按照in-order的方式移動，也不需要class的變數。Java的解法這邊收錄 &lt;a class="link" href="https://leetcode.com/ryanswizzle" target="_blank" rel="noopener"
&gt;ryanswizzle&lt;/a&gt;在Leetcode的解法如下。)&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;public class Solution {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; public boolean isValidBST(TreeNode root) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return isValid(root, null, null);
&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;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; public boolean isValid(TreeNode root, Integer min, Integer max) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if(root == null) return true;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if(min != null &amp;amp;&amp;amp; root.val &amp;lt;= min) return false;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if(max != null &amp;amp;&amp;amp; root.val &amp;gt;= max) return false;
&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; return isValid(root.left, min, root.val) &amp;amp;&amp;amp; isValid(root.right, root.val, max);
&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;}
&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;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item></channel></rss>