題目描述
判斷所給的字符串是否由所給的詞典中的若干個詞組成。
如已知詞典[“code”, “sangfor”, “org”]
則字符串"codesangfororg" 由上述詞典組成,
字符串"codesangforsangfororg" 也由上述詞典組成,
但字符串"sangforcom" 則不由上述詞典組成。
輸入描述:
第一行一個數字K 表示詞典個數
後面若干行則爲具體的輸入詞典,一個詞典一行
最後一行輸入待判定的字符串
輸出描述:
若字符串爲對應的詞典組成,則輸出yes,否則輸出no
示例1
輸入
3
code
sangfor
org
codesangfororg
輸出
yes
示例2
輸入
0
code
輸出
no
看到單串多詞存在性的判斷以爲是AC自動機,後來發現題目要求字典裏的單詞強制存在不允許失配。那感覺就可以用字典樹搞定了,因爲失配直接被判定爲no,所以是在一個長串上不斷匹配已有單詞,重要的是判斷長串匹配過程中單個單詞是匹配完成還是匹配失敗。建樹過程中記錄每個單詞的結尾,匹配過程中若失配了,判斷上一位字符是否是結尾【即失配情況只有可能是匹配完了一個單詞,開始下一個單詞】若是結尾,那麼匹配指針從當前初始化到樹根,從頭匹配,否則直接判定no。
#include <cstdio>
#include <cstring>
using namespace std;
int tot;
int trie[500000][26];
int num[500000];///記錄節點被訪問次數
int insert(char *str,int rt)//建樹
{
for(int j=0; str[j]; j++)
{
int x=str[j]-'a';//第x個分支是這個字母,此層的分支就是x,從x再分出節點
if(trie[rt][x]==0)
{
trie[rt][x]=++tot;//若是未標記的新字母,則重新標號
}
rt=trie[rt][x];
}
num[rt]=1;
}
bool find(char *str,int floor)//查詢字典
{
int rt=floor;
int x,len=strlen(str);
for(int i=0; i<len; i++)
{
x=str[i]-'a';
if(trie[rt][x]==0&&num[rt]!=1)
return false;
if(trie[rt][x]==0&&num[rt]==1)
{
rt=floor;
i--;
continue;
}
rt=trie[rt][x];
}
if(num[rt]==0) return false;
return true;
}
char str[100];
int main()
{
tot=0;///根節點
int floor=++tot;
memset(trie[floor],0,sizeof(trie[floor]));
memset(num,0,sizeof(num));
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",str);
insert(str,floor);
}
char s[15000];
scanf("%s",s);
printf("%s\n",find(s,floor)?"yes":"no");
return 0;
}