深信服2020研發新員工訓練題【組詞】(字典樹單串多詞判斷)

題目描述
判斷所給的字符串是否由所給的詞典中的若干個詞組成。

如已知詞典[“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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章