<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Trie on 跟著 Desolve 學程式</title><link>https://desolve.pages.dev/tags/trie/</link><description>Recent content in Trie on 跟著 Desolve 學程式</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><lastBuildDate>Mon, 09 Dec 2019 00:00:00 +0800</lastBuildDate><atom:link href="https://desolve.pages.dev/tags/trie/index.xml" rel="self" type="application/rss+xml"/><item><title>從LeetCode學演算法 - 73 Trie (2)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-73-trie-2/</link><pubDate>Mon, 09 Dec 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-73-trie-2/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 73 Trie (2)" /&gt;&lt;p&gt;&lt;strong&gt;0208. Implement Trie (Prefix Tree) (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Implement a trie with &lt;code&gt;insert&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, and &lt;code&gt;startsWith&lt;/code&gt; methods.&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;Trie trie = new Trie();
&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;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;trie.insert(&amp;#34;apple&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trie.search(&amp;#34;apple&amp;#34;); // returns true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trie.search(&amp;#34;app&amp;#34;); // returns false
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trie.startsWith(&amp;#34;app&amp;#34;); // returns true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trie.insert(&amp;#34;app&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trie.search(&amp;#34;app&amp;#34;); // returns 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;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may assume that all inputs are consist of lowercase letters &lt;code&gt;a-z&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;All inputs are guaranteed to be non-empty strings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;試實作一個trie，當中包含插入，搜尋，是否含前綴判斷的函式。&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-48-trie-1-533ffdfdc6ac?sk=26fa104e4af5aa5f8bbd986bb756a759" target="_blank" rel="noopener"
&gt;講過一題使用Trie來進行解題的問題&lt;/a&gt;，這次再來複習一下XD&lt;br&gt;
Trie跟樹非常相像，通常用來作字典搜尋，所以又叫做&lt;strong&gt;字典樹&lt;/strong&gt; 。&lt;br&gt;
在實作Trie的時候，我們通常會實作TrieNode作為每個節點的單位，&lt;br&gt;
這當中每個節點主要會記錄兩件事：&lt;br&gt;
&lt;strong&gt;1. 這個節點是否到這邊構成一個字&lt;/strong&gt;&lt;br&gt;
因為可能是經過的節點，比如word -&amp;gt; w, o, r, d，&lt;br&gt;
假設我們插入了一個這樣的字，那麼總共會生成4個節點，&lt;br&gt;
但&lt;strong&gt;只有d&lt;/strong&gt; 這邊應該被判定到此&lt;strong&gt;構成一個字&lt;/strong&gt; 。&lt;br&gt;
所以就這題而言，&lt;br&gt;
我們可以使用一個boolean值(True/False)來儲存這個狀態，&lt;br&gt;
也就是下面程式碼中看到的&lt;strong&gt;isWord&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 這個節點往下連接的節點群&lt;/strong&gt;&lt;br&gt;
以這題來說，由於僅限定a到z，所以我們其實可以用長度為26的節點陣列，&lt;br&gt;
來表達下一個連結。當節點不存在時，表該路徑不存在/尚未生成，&lt;br&gt;
在Java中我們用一個TrieNode[] next來儲存。&lt;/p&gt;
&lt;p&gt;但對Python而言，因為語言特性，&lt;br&gt;
我們無法在TrieNode內直接宣告TrieNode(會報錯)，&lt;br&gt;
所以會選擇使用一個字典進行記錄。&lt;/p&gt;
&lt;p&gt;最後，留意到由於我們每次進行路徑移動時，&lt;br&gt;
所使用的index要嘛是&lt;strong&gt;該字元減去’a’&lt;/strong&gt; (Java)，&lt;br&gt;
要嘛乾脆是&lt;strong&gt;當前的字元&lt;/strong&gt; (Python)，&lt;br&gt;
&lt;strong&gt;所以我們不需要額外耗費空間記錄字元值&lt;/strong&gt; 。&lt;br&gt;
此外，若題目有要求記錄被存入的相同字的次數，&lt;br&gt;
就需要額外的count變數來儲存。(另外可以將isWord改成count用作判斷)&lt;/p&gt;
&lt;p&gt;所以整個的思路就會很明顯了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;定義一個TrieNode class，當中有isWord跟next。&lt;/li&gt;
&lt;li&gt;在Trie中，初始化時宣告一個根節點root的TrieNode。&lt;/li&gt;
&lt;li&gt;insert: 節點從root處開始查找，沿著每個字元連接到下一個TrieNode，&lt;br&gt;
並且如果節點尚未建立就將其建立，走到底後，將isWord設為true。&lt;/li&gt;
&lt;li&gt;search: 一樣從root開始，沿著每個字元往下走，&lt;br&gt;
若碰到沒有建立則可直接回傳false。&lt;br&gt;
當走到該節點以後，依據isWord的狀態來判斷要回傳true or false。&lt;/li&gt;
&lt;li&gt;startWith: 由於只要路過即可，所以前面和search一樣，&lt;br&gt;
但最後只要能走到，即可回傳true。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;p&gt;Java的部分留意到使用了c - &amp;lsquo;a&amp;rsquo;的方式來取得index，&lt;br&gt;
因為char是可以當作正整數來相減的。&lt;br&gt;
TrieNode的建構式理論上可省略，&lt;br&gt;
但直接先寫可以降低編譯器還要幫你生成的麻煩，&lt;br&gt;
Submit實測上似乎平均會快一點點XD&lt;br&gt;
(沒有大量測試，有興趣的讀者可再比較看看)&lt;br&gt;
在最開頭的TrieNode代表著根，&lt;strong&gt;但它本身並不代表任何字元&lt;/strong&gt; ，&lt;br&gt;
請留意這點。&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/3b966e6118553c20154031a162e3e551.js"&gt;&lt;/script&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分額外提供了一個LeetCode上找到解答較快的版本，&lt;br&gt;
是使用#的符號來取代isWord的功能，並用一個多層的字典名為tree，&lt;br&gt;
來記錄整個字典樹的結構。&lt;br&gt;
這個方法的好處是無需另外產生一個TrieNode的物件，&lt;br&gt;
但缺點是&lt;strong&gt;必須使用一個不會出現在字串中的符號&lt;/strong&gt; 。&lt;br&gt;
(如果今天這個字串內會含#的話，這個解就會無法使用了XD)&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/b4e01ea397d5aa9c468a449fbbae5c17.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;
 搜尋：O(N)/O(1)&lt;br&gt;
 前綴：O(N)/O(1)&lt;br&gt;
 當中N代表字串長。)&lt;/p&gt;
&lt;p&gt;「如果要支援刪除呢？」&lt;br&gt;
(要實作刪除函式時，不是使用TrieNode的話，&lt;br&gt;
就要留意去處理自己製造的結束標記。&lt;br&gt;
一般使用TrieNode很簡單，使用search找到該字，&lt;br&gt;
並將isWord設成false/False即可。&lt;br&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限額5名優惠(額滿即截止)：&lt;/strong&gt; &lt;a class="link" href="https://hiskio.com/courses/319?promo_code=VE9NJQE" target="_blank" rel="noopener"
&gt;&lt;strong&gt;https://hiskio.com/courses/319?promo_code=VE9NJQE&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;問卷抽書＆取得上架通知：&lt;/strong&gt; &lt;a class="link" href="https://pse.is/MS2J2?fbclid=IwAR2PMTGbMG-8qh2eq-kfGoolRWWYMPcEXdOa1Bib_pFFUaPlTlGb3UYAeDw" target="_blank" rel="noopener"
&gt;&lt;strong&gt;https://pse.is/MS2J2&lt;/strong&gt; &lt;/a&gt;&lt;br&gt;
如果你對線上課程不放心，&lt;br&gt;
也可以先來&lt;strong&gt;12/17(二)&lt;/strong&gt; 我在天瓏分享的講座看看！&lt;br&gt;
&lt;strong&gt;講座連結：&lt;/strong&gt; &lt;a class="link" href="https://pse.is/JS3LJ?fbclid=IwAR2j615ajqdqNsNHWTST4JnlCdbQzQecNaZG9LV7J55VFnw8ufLWojrk7iw" target="_blank" rel="noopener"
&gt;&lt;strong&gt;https://pse.is/JS3LJ&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;</description></item><item><title>從LeetCode學演算法 - 48 Trie (1)</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/</link><pubDate>Wed, 11 Sep 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 48 Trie (1)" /&gt;&lt;p&gt;&lt;strong&gt;0819. Most Common Word (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 paragraph and a list of banned words, return the most frequent word that is not in the list of banned words. It is guaranteed there is at least one word that isn’t banned, and that the answer is unique.&lt;/p&gt;
&lt;p&gt;Words in the list of banned words are given in lowercase, and free of punctuation. Words in the paragraph are not case sensitive. The answer is in lowercase.&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;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-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;paragraph = &amp;#34;Bob hit a ball, the hit BALL flew far after it was hit.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;banned = [&amp;#34;hit&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Output: &amp;#34;ball&amp;#34;
&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;&amp;#34;hit&amp;#34; occurs 3 times, but it is a banned word.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;ball&amp;#34; occurs twice (and no other word does), so it is the most frequent non-banned word in the paragraph.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Note that words in the paragraph are not case sensitive,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;that punctuation is ignored (even if adjacent to words, such as &amp;#34;ball,&amp;#34;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;and that &amp;#34;hit&amp;#34; isn&amp;#39;t the answer even though it occurs more because it is banned.
&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;&lt;code&gt;1 &amp;lt;= paragraph.length &amp;lt;= 1000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0 &amp;lt;= banned.length &amp;lt;= 100&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;= banned[i].length &amp;lt;= 10&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The answer is unique and written in lowercase (even if its occurrences in &lt;code&gt;paragraph&lt;/code&gt; may have uppercase symbols, and even if it is a proper noun.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;paragraph&lt;/code&gt; only consists of letters, spaces, or the punctuation symbols &lt;code&gt;!?',;.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;There are no hyphens or hyphenated words.&lt;/li&gt;
&lt;li&gt;Words only consist of letters, never apostrophes or other punctuation symbols.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;給定一個段落和一個被禁止的字的列表，回傳這個段落裡面出現次數最高且沒有在禁止字列表內的字。&lt;br&gt;
(題目保證至少有一個字不會被禁止且答案只會有一個)&lt;/p&gt;
&lt;p&gt;禁止字表會以小寫字給定且不需考慮標點符號，&lt;br&gt;
在段落中的字並不限定大小寫(也就是視作相同的字)，&lt;br&gt;
答案要用小寫表示。&lt;/p&gt;
&lt;p&gt;這題一般而言會使用HashMap或dict來解題，&lt;br&gt;
但隨著總字數的增加，一些重複的字母不斷出現感覺其實相對浪費，&lt;br&gt;
所以今天就要專門來介紹一個資料結構來解決這個問題，&lt;br&gt;
這個資料結構就是字典樹(Trie)。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/image-001.png"
width="250"
height="234"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/image-001_hu_7c238d0426cf4426.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/image-001_hu_fbcd3fbed74550c7.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="106"
data-flex-basis="256px"
&gt;&lt;/p&gt;
&lt;p&gt;Trie (From Wikipedia)&lt;/p&gt;
&lt;p&gt;字典樹長得基本上就是樹的一種，通常儲存的是字串。&lt;br&gt;
其&lt;strong&gt;根節點代表著空字串&lt;/strong&gt; ，而每個連結出去的節點，&lt;br&gt;
都代表在前面的基礎上&lt;strong&gt;加上一個字元(char)&lt;/strong&gt; 。&lt;br&gt;
換句話說，我們只要知道從根到葉走了哪些鏈結，&lt;br&gt;
就知道最終葉所代表的字串是什麼，如上圖所示。&lt;/p&gt;
&lt;p&gt;在這題當中，我們可以自行定義一個class TrieNode，&lt;br&gt;
當中包含了&lt;strong&gt;links&lt;/strong&gt; (從這個節點連出去26個字母)，&lt;br&gt;
&lt;strong&gt;cnt&lt;/strong&gt; (這個字在整個段落出現的次數)，以及&lt;strong&gt;word&lt;/strong&gt; (實際上這個字是什麼)。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;其實word可以如上面所說一步一步加起來，&lt;br&gt;
不過寫起來稍微麻煩一點點，這邊就讓我偷懶一下吧XD&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在Java的部分，設定條件是：&lt;br&gt;
當被要求大多數的字串處理函式都禁止使用時，&lt;br&gt;
該怎麼一步一步寫出我們所要的東西。&lt;/p&gt;
&lt;p&gt;首先要建TrieNode，除了上面所述外，我們需要三個函式：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. insert&lt;/strong&gt;&lt;br&gt;
透過每個字母沿links的路徑走，&lt;br&gt;
如果&lt;strong&gt;curr.links[index] == null&lt;/strong&gt; 則表示前面還沒走過，&lt;br&gt;
要自行new出來，並設定其word變數。&lt;br&gt;
在走到底的時候我們要將&lt;strong&gt;cnt數加1&lt;/strong&gt; 。&lt;br&gt;
(代表這個word出現在段落裡次數加1次)&lt;/p&gt;
&lt;p&gt;行走的路徑如之前提過的，直接&lt;strong&gt;使用字元來減去’a’&lt;/strong&gt; 即可，&lt;br&gt;
這邊將&lt;strong&gt;links[0]視為是’a’，而links[25]視為是’z’&lt;/strong&gt; 。&lt;br&gt;
當走到某一條links[index]還沒初始化時，&lt;br&gt;
就將其初始化並給定其word值。&lt;br&gt;
每次往下走時&lt;strong&gt;不要忘記將用來迭代到下一個字元的curr指到下一個位置&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. ban&lt;/strong&gt;&lt;br&gt;
只要將該string對應的TrieNode中的&lt;strong&gt;cnt設成零&lt;/strong&gt; 即可。&lt;br&gt;
如果在走的路徑途中遇到null，表示段落裡不存在這個string，&lt;br&gt;
直接return即可。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. findMax&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;遍歷所有TrieNode並找到最大的cnt及對應的word。&lt;/strong&gt;&lt;br&gt;
(這邊使用到&lt;strong&gt;res作為結果&lt;/strong&gt; 的字串及&lt;strong&gt;maxcnt作為儲存當前最大值的變數&lt;/strong&gt; )&lt;br&gt;
只需要從root的位置開始，往下搜尋有cnt的值，&lt;br&gt;
一一比較即可，當這層搜尋完時，&lt;br&gt;
我們還要往下一層去，所以用迴圈往下再進行遞迴。&lt;br&gt;
(這部分是&lt;strong&gt;DFS&lt;/strong&gt; )&lt;/p&gt;
&lt;p&gt;回到&lt;strong&gt;mostCommonWord&lt;/strong&gt; 函式中，&lt;br&gt;
我們先產生一個&lt;strong&gt;StringBuilder(命名為st)&lt;/strong&gt; 及一個&lt;strong&gt;root(TrieNode)&lt;/strong&gt; ，&lt;br&gt;
並用&lt;strong&gt;isString&lt;/strong&gt; 來表示現在st是否構成一個word。&lt;br&gt;
每次將paragraph中的字元取出來，檢查其是否是大小寫字母，&lt;br&gt;
並將字母統一成小寫後接到st上；&lt;br&gt;
一旦發現&lt;strong&gt;遇到非大小寫字母的字元，且設定的isString為真&lt;/strong&gt; ，&lt;br&gt;
則表示現在st構成一個word，將其丟進root中插入到字典樹內。&lt;br&gt;
(&lt;strong&gt;不要忘記最後面還要再檢查一次&lt;/strong&gt; ，&lt;br&gt;
因為有可能還沒插入就離開迴圈了)&lt;br&gt;
接著再&lt;strong&gt;ban&lt;/strong&gt; 及&lt;strong&gt;findMax&lt;/strong&gt; 後，就可以回傳&lt;strong&gt;res&lt;/strong&gt; 作為答案了!&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/5a957c601c54e428ebf3a84523a34694.js"&gt;&lt;/script&gt;
&lt;p&gt;Python的部分思路跟Java相近，&lt;br&gt;
不過因直譯器的特性，這邊選擇將對應的函式拉到class Solution來做。&lt;br&gt;
讀者可以兩邊互相對照看看差異。&lt;br&gt;
此外，由於banned測資似乎存在會重複的狀況，&lt;br&gt;
所以可以使用set來縮小總長。&lt;/p&gt;
&lt;p&gt;另這邊也提供leetcode上lee215的解：&lt;br&gt;
使用&lt;strong&gt;re.findall&lt;/strong&gt; ，用正規表示式直接將words找出，&lt;br&gt;
再利用Counter直接計算頻率，最終取出最高頻率的字。&lt;br&gt;
(應該是目前最快的解法)&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/ff1fdb1e33d75ce7a991d3e4eb21ba20.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「時間/空間複雜度？」&lt;br&gt;
可以從不同面向來考慮。由於有點長，且不好解釋，&lt;br&gt;
這邊直接貼筆者在leetcode上回答的內容。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/image-001.png"
width="250"
height="234"
srcset="https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/image-001_hu_7c238d0426cf4426.png 480w, https://desolve.pages.dev/post/learn-algorithm-from-leetcode-48-trie-1/image-001_hu_fbcd3fbed74550c7.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="106"
data-flex-basis="256px"
&gt;&lt;/p&gt;
&lt;p&gt;「這個解法有沒有再更優化的方法？」&lt;br&gt;
(至少有兩個，如果讀者有興趣的話可以嘗試看看：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;將word的部分去除(也就是只使用中間的鏈結來取得整個字)&lt;/li&gt;
&lt;li&gt;其實可以&lt;strong&gt;先做ban再作insert&lt;/strong&gt; (ban可將cnt設為**-1** ，而insert時先檢查cnt是否為-1，是的話可以直接跳過)&lt;br&gt;
(這個方法可以同步在insert時更新res和maxcnt，所以會變成先ban再insert完以後，就可以直接回傳答案了，速度應該會再快一點點。))&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;「Java如果允許使用split呢？」&lt;br&gt;
(可以這樣用：&lt;br&gt;
&lt;strong&gt;String[] words = paragraph.toLowerCase().split(“[ !?’,;.]+”);&lt;/strong&gt; 當然，前提是你不要中間的標點符號漏打XD)&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></channel></rss>