給出乙個由s(最多4000個)個不同單詞組成的字典和乙個長字串。把這個字串按字典分解成若干個單詞的連線,有多少種方法?(方法數可能很多,結果對20071027取模)你會怎麼做呢?去一一比較嗎?這也太傻了誒。比如有4個單詞:a、b、cd、ab,則abcd有兩種分解方法:a+b+cd和ab+cd。(字典中單詞個數不超過4000)
【輸入】
abcd
4 a
b cd
ab 【輸出】
case 1: 2
所以就有種叫做字典樹的東西啦!
字典樹(trie),又稱字首樹。是查詢樹的一種。主要用於大量字串的儲存,查詢。搜尋引擎通常利用字典樹完成使用者的搜尋提示。
比如像這樣的圖,tea,ted,ten,to,inn就被我分解成了乙個這樣的樹,也就是說,字典樹在本質上是一棵26叉樹。當你要找乙個單詞是,就是從第乙個字母開始往下找,直到找到葉子,就找到了這個單詞。
那麼具體怎麼實現呢?
先以引題為例子,
1.用d[i]表示以第i個字元到字串末尾的字串能夠分解得單詞數,
2.假設在s[i…length(s)]中,僅發現s[i…n]是字典中出現的單詞,n是該單詞的長度,此時d[i]=d[i+n],(這裡該怎麼理解呢?這樣說,因為該單詞是僅發現的,說明從i到n裡有也只有這麼乙個單詞不能再拆分了,所以d[i]=1*d[i+n])
3.所以,d[i]=sum(d[i+len(x)]),假定x是乙個出現的字首字串(2中的s[i…n])
4.但是,如果列舉x,再判斷它是否為s[i…len]的字首,複雜度是o(4000*len);
那麼,字典樹!
以該圖為例
我們很容易發現字典樹有以下幾個特點:
1.根節點為空,
2.內節點一般為字元
3.葉子結點就是往下搜到的單詞結點
然後呢,用兩個陣列來儲存這棵樹
1.ch[i][j]=x,表示第i號結點的子結點序號是x,儲存的字元的ascii碼是j;
2.val[i],表示第i號結點的附加資訊,比如val[i]>0表示i是單詞結點。(這個val陣列是要你自己在造樹的時候遇到葉子結點再把它手動賦值為大於0)
接下來展示字典樹的插入和查詢
const
int maxnode = 400*100+10;
const
int sigma=26;
struct tire
int idx(char c) ;
void insert(char *s, int v);
void find(char *s);
}void insert(char *s, int v) //v是附加資訊,0表示「非單詞結點」
u = ch[u][c];//接下來的字元則是以u為根節點往下延伸了,就是比如說beautiful,當e作為b的子節點之後,就要去做a是e的子節點了
}val[u]=v;
} void find(const
char *s, int len, vector
& ans)
}} char str[30001], tmp[101];
int d[30001];
trie t;
int main()
printf("case %d: ",case++);
solve();
}return0;}
void solve()
}printf("%d\n",d[0]);
}
啊 字典樹 Trie樹(持續更新)
今天開始學習字典樹,順便做做筆記,等多刷幾道題再來更新一波經驗 字典樹,又稱單詞查詢樹 字首樹 鍵樹,是一種樹形結構,是一種雜湊樹的變種。1 根節點不包含字元,除根節點外每乙個節點都只包含乙個字元。2 從根節點到某一節點,路徑上經過的字元連線起來,為該節點對應的字串。3 每個節點的所有子節點包含的字...
01字典樹(待更新)
01字典樹典型的題就是找出異或值最大的兩個數,其實跟字典樹差不多的,就是從原來的26位字母變成了0和1,插入操作也跟字典樹差不多,查詢的時候有貪心思想,盡量找同位不相同的。模板 1 include2 include3 include4 include5 using namespace std 67 ...
Trie樹(字典樹)
trie樹的核心思想是用空間換時間,通過在樹中儲存字串的公共字首,來達到加速檢索的目的。例如,對於一棵儲存由英文本母組成的字串的trie樹,如下圖 trie樹在實現的時候,可以用左兒子右兄弟的表示方法,也可以在每個節點處開設乙個陣列,如上圖的方法。trie樹的主要操作是插入 查詢,也可以進行刪除。插...