給出n
nn個字串,以及m
mm個詢問。每次詢問讀入乙個字串,求該字串是多少個字串的字首。
每個字串長度小於102
10^2
102,n和m小於105
10^5
105。
【輸入】
4anan
amnaman
anann
3ana
amaa
【輸出】21
4樸素演算法:暴力搜尋,對於每個詢問,把所有的n個字串搜尋一遍,統計答案。時間複雜度大於1010
10^10
10。顯然,這樣時間是非常大的。
所以我們需要使用字典樹。
字典樹,顧名思義,首先它是一棵樹。
而且它是用來儲存字串的!!!
它的根節點為空,其餘每個節點代表乙個字元。從根節點開始,沿著一定的路徑,加上沿途遇到的字元,到達每個節點,都能得到對應的乙個字串。
設f [i
][c]
f[i][c]
f[i][c
]表示字典樹中編號i
ii節點的兒子中,表示字元c
cc的兒子的編號。
為了節約空間,只有建樹時需要用到的節點,才會被開啟,其餘都是不存在的。(這句話如果不好理解可以看看操作步驟和**)
當前我們將字串s[k
]s[k]
s[k]
加入字典樹,步驟如下:
1、字串從左往右,對應地從字典樹的根節點開始往下走;
2、如果當前的f[i
][s[
k][j
]]f[i][s[k][j]]
f[i][s
[k][
j]]為0,說明這個節點還未被開啟,將節點總數num
+1num+1
num+
1,然後f[i
][s[
k][j
]]=n
umf[i][s[k][j]]=num
f[i][s
[k][
j]]=
num;
3、繼續往下走到對應的兒子節點。i=f
[i][
s[k]
[j]]
i=f[i][s[k][j]]
i=f[i]
[s[k
][j]
],j+
1j+1
j+1。
4、當走完整個字串時,給當前的節點i
ii向k
kk連一條邊,表示字串s[k
]s[k]
s[k]
的終點在節點iii。
建樹可以用遞迴實現,也可以用迴圈實現。以下貼上遞迴**,迴圈類似。
void
make
(int i,
int j)
else
}for
(k=1
;k<=n;k++
)
如前面的樣例,四個字串用字典樹儲存的效果。
由上圖顯而易見,當多個字串有相同字首時,相同的字元只會儲存一次,節省了很大的空間。
同時,用字典樹儲存字串,可以對許多關於字串字首的題目有很大幫助。
顯然,這題我們需要先用n
nn個字串建立一棵字典樹。
與此同時,記錄sum
[i]sum[i]
sum[i]
表示n
nn個字串中字首為str
ing[
i]string[i]
string
[i]的個數,str
ing[
i]string[i]
string
[i]為字典樹中到節點i
ii處所表示的字串(此處只是為了方便說明,在實現時這個str
ingstring
string
陣列並不存在)。每到乙個節點i
ii,就給sum
[i]+
1sum[i]+1
sum[i]
+1。如何處理詢問?
將詢問串放入字典樹中,類似建樹的方式往下走。如果對應的節點不存在,則直接返回並輸出000.
否則一直走到該串的末尾,對應的sum
[i]sum[i]
sum[i]
即為答案。
此時,相信你已經學會了。字典樹模板都是一樣的,對於不同的題目不同的要求,都以模板為基礎,再按需新增各種操作,難題便迎刃而解。
面對更多的困難與挑戰,需要你更多思考、靈活變通,一切都不是問題!
Trie字典樹 基本操作
給出n nn個字串,以及m mm個詢問。每次詢問讀入乙個字串,求該字串是多少個字串的字首。每個字串長度小於102 10 2 102,n和m小於105 10 5 105。輸入 4anan amnaman anann 3ana amaa 輸出 21 4樸素演算法 暴力搜尋,對於每個詢問,把所有的n個字串...
Trie樹(字典樹)
trie樹的核心思想是用空間換時間,通過在樹中儲存字串的公共字首,來達到加速檢索的目的。例如,對於一棵儲存由英文本母組成的字串的trie樹,如下圖 trie樹在實現的時候,可以用左兒子右兄弟的表示方法,也可以在每個節點處開設乙個陣列,如上圖的方法。trie樹的主要操作是插入 查詢,也可以進行刪除。插...
字典樹 Trie樹
字典樹 trie樹 顧名思義是一種樹形結構,屬於雜湊樹的一種。應用於統計 排序 查詢單詞 統計單詞出現的頻率等。它的優點是 利用字串的公共字首來節約儲存空間,最大限度地減少無謂的字串比較,查詢效率比雜湊表高。字典樹的結構特點 根節點不代表任何字元。其他節點從當前節點回溯到根節點可以得到它代表的字串。...