「算法與數據結構」Trie樹之美

2021-03-06 前端UpUp
前言

這次分享的Trie字典樹,是數據結構專題中的一個分支,認識了解Trie這種樹型數據結構,對構建算法與數據結構知識體系有一定的幫助。

我對Trie樹的理解:把字符串都串接起來,消滅不必要的存儲,利用的就是字符串的公共前綴。

其實對於它的理解,你理解了這句話即可👇

利用字符串的公共前綴來減少查詢時間,最大限度的減少無謂的字符串比較,查詢效率比哈希樹高。

如果你還不了解什麼是Trie數據結構的話,或者知道一些,但是對於它具體是如何實現一個簡單Trie樹時,那麼這篇文章可能適合你閱讀。

那麼圍繞以下幾個點來展開介紹Trie樹👇

聯繫👉TianTianUp,遇到問題的話,可以聯繫作者噢,願意陪你一起學習一起探討問題。

基本概念

首先,我們對Trie樹得做一些基本的了解。Trie樹中文名叫字典樹,前綴樹等,接下來我就以字典樹稱呼。

我們來看下維基百科對它的描述吧⬇️

在計算機科學中,trie,又稱前綴樹字典樹,是一種有序樹,用於保存關聯數組,其中的鍵通常是字符串。與二叉查找樹不同,鍵不是直接保存在節點中,而是由節點在樹中的位置決定。一個節點的所有子孫都有相同的前綴,也就是這個節點對應的字符串,而根節點對應空字符串。一般情況下,不是所有的節點都有對應的值,只有葉子節點和部分內部節點所對應的鍵才有相關的值。

樸實無華的描述,其實我們看一張圖就能看明白了~,我在網上找了一張不錯的圖,具體的出處,這裡就不補充了,因為實在找不到原作者~

字典樹圖解1

這裡需要說明的內容就是,一般而言,應該是用一個點來表示一個字符,這裡為了更好的說明,所以我就是用邊來描述字符

可以發現,這棵字典樹用邊來代表字母,而從根結點到樹上某一結點的路徑就代表了一個字符串。舉個例子, 1→2→6表示的就是字符串 aba 。

再比如,1→4→8構成的字符串是ca,那麼如果在往下拓展的話,我們是不是有 caa,cab,那麼他們都會經過1→4→8,這些路徑,說明他們是有一段公共的前綴,這個前綴的內容就是ca,說道這裡,我們就知道字典樹利用的就是字符串的前綴來解決問題。

那麼具體它有哪些性質的話,我們下文介紹一下~

基本性質

對於上述概念有了一定的理解後,我們接下來就看下Trie樹的基本性質。

可以根據這個,大體上分成三個點來說👇

根節點不包含字符,除根節點外,每個節點只包含一個字符。從根節點到某一個節點,路徑上經過的字符連接起來,為該節點對應的字符串。

接下來我們可以稍微分析一下,可以結合一個圖來看看👇

我們通過拿how,hi,her,hello,so,see這6個字符串構造出來的就是下面圖這個樣子。

圖解Trie樹

(圖片出處不明,網上引用處太多~)

第一個性質:

從圖中也可以看出,根節點是/, 代表的內容也就是空,其他的節點比如,根節點下一個層級,有 h和s,分別代表的是兩個字符。

第二個性質:

從根節點到某一個節點,路徑上經過的字符連接起來,為該節點對應的字符串。

比如how表示的就是一個字符串,hi,也表示的是一個字符串,可是你會不會好奇,he和hel為什麼不能表示一個字符串呢?

當你想到這裡的話,說明你已經看得很仔細,馬上就要掌握它了,確實,從圖中看,我們會發現有些節點顏色不同,這是因為,我們預定好以這個深色的節點代表當前是一個字符串的結尾,想一想,這樣子的作用是啥?

那麼實際代碼中,我們應該如何去約定或者做個標記呢,其實只要設置一個標記位即可。

比如下面這樣子👇

const TrieNode = function () {
  this.next = Object.create(null)
  this.isEnd = false
};

當前的isEnd變量就表示當前的節點是不是結束串,當isEnd為True時,表示從根節點開始,到這個字符,所構成的字符串是存在的,是一個完整的字符串。

第三個性質:

每個節點的所有子節點包含的字符串不相同。

很明顯,我們從根節點開始,依次往下走,會發現,每個節點下面的節點是不相同的,所以依次組成的字符串不可能相同。

應用場景

對Trie樹,有一定了解後,我們就可以看看它有哪些的實際應用場景了。

這裡參考的是網上所提供的幾個點👇

在搜尋引擎中關鍵詞提示,引擎會自動彈出匹配關鍵詞的下拉框,這種應用場景大家應該都很熟悉。

下拉框

那麼應該如何利用一種高效的數據結構存儲呢,這裡就符合字典樹的性質,所以可以利用字典樹來構造特定的數據,達到一種更加快速檢索的效果。

字符串檢索

事先將已知的一些字符串(字典)的有關信息保存到trie樹裡,查找另外一些未知字符串是否出現過或者出現頻率,可以舉例子說明情況👇

1000萬字符串,其中有些是重複的,需要把重複的全部去掉,保留沒有重複的字符串。給出N 個單詞組成的熟詞表,以及一篇全用小寫英文書寫的文章,請你按最早出現的順序寫出所有不在熟詞表中的生詞。

詞頻統計

給定很長的一個串,統計頻數出現次數最多情況,舉個例子👇

有一個1G大小的一個文件,裡面每一行是一個詞,詞的大小不超過16位元組,內存限制大小是1M。返回頻數最高的100個詞。一個文本文件,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前10個詞,請給出思想,給出時間複雜度分析。

字符串最長公共前綴

到現在,我們應該知道,Trie樹利用多個字符串的公共前綴來節省存儲空間,當我們把大量字符串存儲到一棵trie樹上時,我們可以快速得到某些字符串的公共前綴,所以可以利用這個特點來解決一些前綴問題。

非要舉個例子的話,有個例子👇

給出N 個小寫英文字母串,以及Q 個詢問,即詢問某兩個串的最長公共前綴的長度是多少?

應用場景還是有很多的,剩下的可以自行去探索,接下來,我們通過實際的題目來看看,如何構造字典樹吧~

2個例子

接下來,我們通過二個題目作為例子,來看看字典樹在實際應用可以解決哪些問題👇

詞典中最長的單詞⭐

連結:詞典中最長的單詞

給出一個字符串數組words組成的一本英語詞典。從中找出最長的一個單詞,該單詞是由words詞典中其他單詞逐步添加一個字母組成。若其中有多個可行的答案,則返回答案中字典序最小的單詞。

若無答案,則返回空字符串。

示例 1:

輸入:
words = ["w","wo","wor","worl", "world"]
輸出:"world"
解釋: 
單詞"world"可由"w", "wo", "wor", 和 "worl"添加一個字母組成。

示例 2:

輸入:
words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
輸出:"apple"
解釋:
"apply"和"apple"都能由詞典中的單詞組成。但是"apple"的字典序小於"apply"。

提示:

來源:力扣(LeetCode)連結:https://leetcode-cn.com/problems/longest-word-in-dictionary著作權歸領扣網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

這題無非就是找到一個最長的單詞,可以拆分成words數組中某一部分,最暴力的思路就是去枚舉每一項,但是這樣子的時間複雜度是巨大的, 這個時候,我們是不是可以思考一下,這個問題有哪些地方是共性的呢?

沒錯,就是前綴是相同的,從這點來看,是不是就可以利用這個前綴樹,把它數據存儲下來然後遍歷一遍字典樹,只要這顆樹只有一個分支,則表示它有解,如果存在兩個分支以上的話,則無答案。

複雜度分析

這點應該很好理解,這裡就跳過了。

這裡的話,我的解法構造字典樹,當然了,也有其他的解法,這裡就不展開了,可以看下我的代碼噢~

最長的串

代碼點這裡☑️

其實你會發現,構造一個Trie樹的話,是很消耗空間的,有點空間換時間的意思,所以具體得根據實際的題目來解決問題。

實現Trie(前綴樹)⭐⭐

連結:實現 Trie (前綴樹)

實現一個 Trie (前綴樹),包含 insert, search, 和 startsWith 這三個操作。

示例:

Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 true
trie.search("app");     // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");   
trie.search("app");     // 返回 true

說明:

你可以假設所有的輸入都是由小寫字母 a-z 構成的。

來源:力扣(LeetCode)連結:https://leetcode-cn.com/problems/implement-trie-prefix-tree著作權歸領扣網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

這個題目就是典型的寫Trie樹,對於第一次寫這個題目的話,如果沒有思路的話,可以嘗試先看看別人的代碼,看看基本的套路在哪裡。

話不多說,可以參考這份代碼,可以看看如何構造一顆字典樹👇

leetcode-實現Trie樹

代碼點這裡☑️

剩下的刪除操作,還有統計字符串出現的頻率,可以自己來實現一下,這個基本上不難,畫個圖,就知道如何實現啦~

題目是做不完的,做完這些題目後,希望你能對Trie字典樹有所認識,能對它有更加深入的理解~,接下來準備了四道題集,希望對你們有幫助~

詞典中最長的單詞

實現 Trie (前綴樹)

單詞搜索 II

Loading question

❤️ 感謝大家

如果你覺得這篇內容對你挺有有幫助的話:

點讚支持下吧,讓更多的人也能看到這篇內容(收藏不點讚,都是耍流氓 -_-)關注公眾號前端UpUp,聯繫作者,遇到問題的話,歡迎打擾我,我們一起探討一起進步。歡迎聯繫作者噢,微信:DayDay2021,拉你進前端交流群。

相關焦點

  • 「算法與數據結構」二叉樹之美
    前言這次梳理的內容是數據結構專題中的「樹」,如果你看到樹這類數據結構時,滿腦子頭疼,覺得它很難理解,如果是這樣子的話,那麼本文可能對你或許有點幫助。俗話說得好,要想掌握理解的話,我們得先了解它的概念,性質等內容。
  • Trie 樹是什麼樣的數據結構?有哪些應用場景?
    與二叉查找樹不同,鍵不是直接保存在節點中,而是由節點在樹中的位置決定。一個節點的所有子孫都有相同的前綴,也就是這個節點對應的字符串,而根節點對應空字符串。讓我們一起來學習下它吧。一、什麼是Trie樹Trie樹,又叫字典樹、前綴樹(Prefix Tree)、單詞查找樹 或 鍵樹,是一種多叉樹結構。
  • Trie樹結構
    一個節點的所有子孫都有相同的前綴,也就是這個節點對應的字符串,而根節點對應空字符串。一般情況下,不是所有的節點都有對應的值,只有葉子節點和部分內部節點所對應的鍵才有相關的值。Trie這個術語來自於retrieval。根據詞源學,trie的發明者Edward Fredkin把它讀作英語發音:/ˈtriː/ "tree"。
  • 什麼是 Trie 樹?
    節點 n 存在子節點 o,不用重新創建子節點 o。節點 v 不存在子節點 a,創建子節點 a。並將該節點標記為字符串結束標誌,完成 nova 字符串插入。情況一:待刪除的字符串末尾為葉節點,且與其它字符串無公共前綴。將節點逐一刪除即可,例如刪除 cat。情況二:待刪除字符串末尾不是葉節點。將字符串標誌位置為 false 即可,例如刪除 no 。情況三:待刪除字符串末尾為葉節點,並且中間有其它單詞。
  • 深入理解Trie樹
    前言前面的文章介紹過各種高效的的數據結構,比如二叉搜索樹,AVL樹,紅黑樹,B樹,跳躍表等,今天我們再來學習一種多路樹,叫做Trie樹。
  • 數據結構和算法學習指南
    首先,這裡講的都是普通的數據結構和算法,咱不是搞競賽的,野路子出生,只解決常規的問題,以面試為最終目標。另外,以下是我個人的經驗的總結,沒有哪本算法書會寫這些東西,所以請讀者試著理解我的角度,別糾結於細節問題,因為這篇文章就是對數據結構和算法建立一個框架性的認識。
  • 看動畫輕鬆理解「Trie樹」
    雖然發音與「Tree」一致,但為了將這種 字典樹 與 普通二叉樹 以示區別,程式設計師小吳一般讀「Trie」尾部會重讀一聲,可以理解為讀「TreeE」。Trie樹,也叫「字典樹」。顧名思義,它是一個樹形結構。它是一種專門處理字符串匹配的數據結構,用來解決在一組字符串集合中快速查找某個字符串的問題。
  • 圖解:數據結構中的6種「樹」,你心中有數嗎?
    樹形結構相比數組、鍊表、堆棧這些數據結構來說,稍微複雜一點點,但樹形結構可以用於解決很多實際問題,因為現實世界事物之間的關係往往不是線性關聯的,而「樹」恰好適合描述這種非線性關係。今天就帶大家一起學習下,數據結構中的各種「樹」,這也是面試中經常考察的內容,手撕二叉樹是常規套路,對候選人也很有區分度,學完這篇文章,相信大家都會心中有「樹」了。
  • 圖解:計算機數據結構中的 6 種「樹」,你心中有數了嗎?
    檸檬哥整理了50本計算機相關的電子書,關注公眾號「後端技術學堂」,回復「1024」我發給你,回復「進群」拉你進百人讀者技術交流群。樹形結構相比數組、鍊表、堆棧這些數據結構來說,稍微複雜一點點,但樹形結構可以用於解決很多實際問題,因為現實世界事物之間的關係往往不是線性關聯的,而「樹」恰好適合描述這種非線性關係。
  • 圖解:數據結構中的6種「樹」,檸檬問你心中有數嗎?
    樹形結構相比數組、鍊表、堆棧這些數據結構來說,稍微複雜一點點,但樹形結構可以用於解決很多實際問題,因為現實世界事物之間的關係往往不是線性關聯的,而「樹」恰好適合描述這種非線性關係。今天就帶大家一起學習下,數據結構中的各種「樹」,這也是面試中經常考察的內容,手撕二叉樹是常規套路,對候選人也很有區分度,學完這篇文章,相信大家都會心中有「樹」了。從樹說起什麼是樹?現實中的樹大家都見過,在數據結構中也有樹,此樹非彼樹,不過數據結構的樹和現實中的樹在形態上確實有點相像。
  • 圖解:數據結構中的各種「樹」,你都心中有數嗎?
    今天就帶大家一起學習下,數據結構中的各種「樹」,這也是面試中經常考查的內容,手撕二叉樹是常規套路,對候選人也很有區分度,學完這篇文章,相信大家都會心中有「樹」了。從樹說起什麼是樹?現實中的樹大家都見過,在數據結構中也有樹,此樹非彼樹,不過數據結構的樹和現實中的樹在形態上確實有點相像。
  • 「算法與數據結構」一張腦圖帶你看動態划算法之美
    動態規劃只能應用於有最佳子結構的問題。最佳子結構的意思是局部最佳解能決定全域最佳解(對有些問題這個要求並不能完全滿足,故有時需要引入一定的近似)。簡單地說,問題能夠分解成子問題來解決。❞我稍微總結一下👇將一個大的問題拆分成一個個子問題,我們把它稱之為子結構。
  • 「走過」微軟、優步,老工程師告訴你哪些數據結構和算法最重要
    作者:Gergely Orosz機器之心編譯參與:小舟、杜偉數據結構和基礎算法作為計算機科學的必學課程,近幾年卻關注度越來越少。但程式設計師真的不再需要這兩門基礎知識了嗎?由此可見,數據結構和算法並不是如人們所言用處不大。在本文中,Gergely Orosz 列舉了一系列現實世界的實例,包含生產中會用到的樹、圖等數據結構和各種算法。
  • 「機器學習」機器學習算法優缺點對比(匯總篇)
    「換言之,就是沒有算法能完美地解決所有問題,尤其是對監督學習而言(例如預測建模)」。舉例來說,你不能去說神經網絡任何情況下都能比決策樹更有優勢,反之亦然。它們要受很多因素的影響,比如你的數據集的規模或結構。其結果是,在用給定的測試集來評估性能並挑選算法時,你應當根據具體的問題來採用不同的算法。
  • 數據結構與算法-2
    >(4)堆棧、(優先級)隊列(5)map、set(6)樹、圖(7)遞歸、分治、回溯(8)貪心算法(9)BFS、DFS(10)剪枝(11)二分查找(12)Trie樹(13)位運算(14)動態規劃(15)併查集
  • 淺談樹形結構:多叉樹,紅黑樹,堆,Trie樹,B樹,B+樹...
    2.Linux內核的完全公平調度器3.Linux中epoll機制的實現…堆堆是一種特殊的數據結構,它滿足兩個特性:堆是一個完全二叉樹;堆中每一個節點的排序值都必須大於等於(或小於等於)其左右子節點的排序值。這裡解釋一下完全二叉樹。
  • 計算機專業應數據結構和算法至上?還是與業務掛鈎的技術至上?
    數據結構和算法:決定大廠面試成敗的關鍵Pascal之父尼古拉斯·沃斯曾靠一個公式「算法+數據結構=程序」獲得了冠有計算機界諾貝爾獎之稱的圖靈獎。從這個公式中不難看出,編程從本質上來說就是算法加數據結構,而算法是編程思想的核心部分。
  • 算法一看就懂之「 數組與鍊表 」
    數據結構是我們軟體開發中最基礎的部分了,它體現著我們編程的內功。大多數人在正兒八經學習數據結構的時候估計是在大學計算機課上,而在實際項目開發中,反而感覺到用得不多。但別人封裝好了不代表我們就可以不關注了,數據結構作為程式設計師的內功心法,是非常值得我們多花時間去研究的,我這就翻開書複習複習:本文就先從大家最經常使用的「 數組 」和「 鍊表 」聊起。不過在聊數組和鍊表之前,咱們先看一下數據的邏輯結構分類。通俗的講,數據的邏輯結構主要分為兩種:知道了分類,下面我們來詳細看一下「 數組 」和「 鍊表 」的原理。
  • 微軟、優步,老工程師告訴你哪些數據結構和算法最重要
    作者:Gergely Orosz機器之心編譯參與:小舟、杜偉數據結構和基礎算法作為計算機科學的必學課程,近幾年卻關注度越來越少。但?由此可見,數據結構和算法並不是如人們所言用處不大。在本文中,Gergely Orosz 列舉了一系列現實世界的實例,包含生產中會用到的樹、圖等數據結構和各種算法。值得肯定的,所有這些都出自他的第一手經驗,藉此希望表達他的觀點,即通用數據結構和算法知識並不只是「為了面試」,而是你在快速成長的創新型科技公司工作時,可能會經常遇到的東西。
  • 算法一看就懂之「 插入排序 」
    「 冒泡排序 」了,今天咱們來看一看「 插入排序 」。「 插入排序 」與「 冒泡排序 」一樣都屬於時間複雜O(n*n)的排序算法,並且也都是基於元素之間比較的方式來完成排序的。不過「 插入排序 」比「 冒泡排序 」在實際應用中更廣泛一些,因為它的執行效率更高一點。一、「 插入排序 」是什麼?