POJ 1035 Spell checker (trie树)

题目大意:给一系列字符串,构成一个词典,然后有若干询问,每个询问为一个字符串x,问字符串是否在词典中,若在则输出x is correct,否则,通过删除x中的某个字符,或者替换x中的某个字符,或者在x中的插入一个字符,使得得到的新字符在词典中,全部输出。输出时要按照词典中字符串的存在顺序。(词典中最多有10000个单词,字符串的长度最大为15,最多有50个询问。)

简单的trie树应用。每个结点存一个bool值,判断其是否是单词。对于删除,替换,插入字符这些操作,只需对询问的字符x的所有这写操作枚举出来,然后在字典树上查找即可。

对于输出,若为correct,直接输出,否则用set把答案存起来,枚举词典中的单词,若在set里,则输出,同时把他在set里删掉。

数组模拟链表:

#include <iostream>
#include <set>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define SIZE 130000
#define N 26

int c[SIZE][N],idx;
int vis[SIZE];
bool isWord[SIZE];
char word[10010][N],input[N];
int tot;
set <string> st;
set <string>::iterator it;

void update(char *str)
{
    int len = (int)strlen(str);
    int p = 0;
    for(int i=0; i<len; i++)
    {
        vis[p]++;
        if(c[p][str[i]-'a'] == 0)
        {
            ++idx;
            c[p][str[i]-'a'] = idx;
        }
        p = c[p][str[i]-'a'];
    }
    vis[p]++;
    isWord[p] = true;
}

bool search(char *str)
{
    int len = (int)strlen(str);
    int p = 0;
    for(int i=0; i<len; i++)
    {
        if(c[p][str[i]-'a'] == 0)
            return false;
        p = c[p][str[i]-'a'];
    }
    return isWord[p];
}

int main()
{
    memset(c,0,sizeof(c));
    memset(vis,0,sizeof(vis));
    memset(isWord,0,sizeof(isWord));
    idx = tot = 0;
    while(scanf("%s",input))
    {
        if(strcmp(input,"#") == 0)
            break;
        update(input);
        ++tot;
        strcpy(word[tot],input);
    }
    while(scanf("%s",input))
    {
        if(strcmp(input,"#") == 0)
            break;
        if(search(input))
            printf("%s is correct\n",input);
        else
        {
            int len = (int)strlen(input);
            char fuck[N<<1];
            int id;
            st.clear();
            if(len > 1)
            {
                for(int i=0; i<len; i++) //delete
                {
                    id = 0;
                    for(int k=0; k<len; k++)
                    {
                        if(k == i)continue;
                        fuck[id++] = input[k];
                    }
                    fuck[id] = '\0';
                    if(search(fuck))
                        st.insert(fuck);
                }
            }
            for(int i=0; i<len; i++)
            {
                strcpy(fuck,input);
                fuck[len] = '\0';
                for(int k=0; k<N; k++)
                {
                    fuck[i] = k+'a';
                    if(search(fuck))
                        st.insert(fuck);
                }
            }
            for(int i=0; i<=len; i++)
            {
                for(int p=0; p<i; p++)
                    fuck[p] = input[p];
                for(int p=i+1; p<=len; p++)
                    fuck[p] = input[p-1];
                for(int k=0; k<N; k++)
                {
                    fuck[i] = k+'a';
                    fuck[len+1] = '\0';
                    if(search(fuck))
                        st.insert(fuck);
                }
            }
            printf("%s: ",input);
            if(st.empty())
            {
                puts("");
                continue;
            }
            for(int i=1; i<=tot; i++)
            {
                if(st.empty())
                    break;
                it = st.find(word[i]);
                if(it != st.end())
                {
                    cout << *it;
                    st.erase(*it);
                    if(!st.empty())
                        printf(" ");
                }
            }
            puts("");
        }
    }
    return 0;
}

孩子兄弟表示法:

#include <iostream>
#include <set>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define N 26

struct node
{
	int c;
	int son,bro;
	bool isWord;
}trie[150000];
int idx;
char word[10010][N];
set <string> st;
set <string>::iterator it;

void update(char *str)
{
	int len = (int)strlen(str);
	int p = 0;
	for(int i=0; i<len; i++)
	{
		if(trie[p].son == 0)
		{
			trie[++idx].c = str[i]-'a';
			trie[idx].son = trie[idx].bro = 0;
			trie[idx].isWord = false;
			trie[p].son = idx;
			p = idx;
		}
		else
		{
			p = trie[p].son;
			while(trie[p].c != str[i]-'a' && trie[p].bro)
				p = trie[p].bro;
			if(trie[p].c != str[i]-'a')
			{
				trie[++idx].c = str[i]-'a';
				trie[idx].son = trie[idx].bro = 0;
				trie[idx].isWord = false;
				trie[p].bro = idx;
				p = idx;
			}
		}
	}
	trie[p].isWord = true;
}

bool search(char *str)
{
	int len = (int)strlen(str);
	int p = trie[0].son;
	for(int i=0; i<len; i++)
	{
		 while(trie[p].c != str[i]-'a' && trie[p].bro)
		 	p = trie[p].bro;
		 if(trie[p].c != str[i]-'a')
		 	return false;
		 if(i + 1 == len)
		 	break;
		 if(trie[p].son)
		 	p = trie[p].son;
		 else
		 	return false;
	}
	return trie[p].isWord;
}

int main()
{
	trie[0].son = trie[0].bro = 0;
	trie[0].isWord = false;
	idx = 0;
	char w[N];
	int tot = 0;
	while(scanf("%s",w))
	{
		if(strcmp(w,"#") == 0)
			break;
		update(w);
		++tot;
		strcpy(word[tot],w);
	}
	while(scanf("%s",w))
	{
		if(strcmp(w,"#") == 0)
			break;
		if(search(w))
			printf("%s is correct\n",w);
		else
		{
			st.clear();
			int len = (int)strlen(w);
			char ww[N];
			int id;
			for(int i=0; i<len; i++) //delete a letter
			{
				id = 0;
				for(int k=0; k<len; k++)
				{
					if(k == i)continue;
					ww[id++] = w[k];
				}
				ww[id] = '\0';
				if(search(ww))
					st.insert(ww);
			}
			for(int i=0; i<len; i++) // replace a letter
			{
				strcpy(ww,w);
				for(int k=0; k<N; k++)
				{
					ww[i] = k+'a';
					ww[len] = '\0';
					if(search(ww))
						st.insert(ww);
				}
			}
			for(int i=0; i<=len; i++) // add a letter
			{
				for(int k=0; k<i; k++)
					ww[k] = w[k];
				for(int k=i+1; k<=len; k++)
					ww[k] = w[k-1];
				for(int k=0; k<N; k++)
				{
					ww[i] = k+'a';
					ww[len+1] = '\0';
					if(search(ww))
						st.insert(ww);
				}
			}
			printf("%s: ",w);
			if(st.empty())
			{
				puts("");
				continue;
			}
			for(int i=1; i<=tot; i++)
			{
				it = st.find(word[i]);
				if(it != st.end())
				{
					cout << *it;
					if(!st.empty()) printf(" ");
				}
				if(st.empty())
					break;
			}
			puts("");
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值