bzoj 1819 (字典树)

1819: [JSOI]Word Query电子字典

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 1097   Solved: 365
[ Submit][ Status][ Discuss]

Description

人们在英文字典中查找某个单词的时候可能不知道该单词的完整拼法,而只知道该单词的一个错误的近似拼法,这时人们可能陷入困境,为了查找一个单词而浪费大量的时间。带有模糊查询功能的电子字典能够从一定程度上解决这一问题:用户只要输入一个字符串,电子字典就返回与该单词编辑距离最小的几个单词供用户选择。 字符串a与字符串b的编辑距离是指:允许对a或b串进行下列“编辑”操作,将a变为b或b变为a,最少“编辑”次数即为距离。  删除串中某个位置的字母;  添加一个字母到串中某个位置;  替换串中某一位置的一个字母为另一个字母; JSOI团队正在开发一款电子字典,你需要帮助团队实现一个用于模糊查询功能的计数部件:对于一个待查询字符串,如果它是单词,则返回-1;如果它不是单词,则返回字典中有多少个单词与它的编辑距离为1。

Input

第一行包含两个正整数N (N < = 10,000)和M (M < = 10,000)。 接下来的N行,每行一个字符串,第i + 1行为单词Wi。单词长度在1至20之间。再接下来M行,每行一个字符串,第i + N + 1表示一个待查字符串Qi。待查字符串长度在1至20之间。Wi和Qi均由小写字母构成,文件中不包含多余空格。所有单词互不相同,但是查询字符串可能有重复。 提示:有50%的数据范围:N < = 1,000,M < = 1,000。

Output

输出应包括M行,第i行为一个整数Xi。Xi = -1表示Qi为字典中的单词;否则Xi表示与Qi编辑距离为1的单词的个数。

Sample Input

4 3
abcd
abcde
aabc
abced
abcd
abc
abcdd

Sample Output

-1
2
3

HINT

abcd在单词表中出现过;abc与单词abcd、aabc的编辑距离都是1;abcdd与单词abcd、abcde、abced的编辑距离都是1。

 这道题的意思 还是很明确的把  就不多解释了

先讲讲思路吧::

1.首先用字典树哈希给你的n个字符串不用说 (不懂字典树的小伙伴可以先去学习一波~~)  

2.读入m个询问字符串之后,利用字典树来查找看是否存在 如果存在输出-1

3.如果不存在  暴力 枚举所有情况  加一个字母  删掉一个字母  改一个字母 这三种操作

4.在枚举的时候你可能会在不同的地方采取了添加字符操作  然后得到了相同的 字符串  所以你需要一个判重

这道题我写的时候写了两遍  两次都是一个错误卡了我一天 真的恶心人

第一次 用的string  然后RE  莫名其妙~~

第二次 我用了char数组  这时候发现了一个巨坑的点  我没有注意 是这样的  如果你开了一个数组  然后这个数组是一个临时变量 那么这个数组并不是初始化里面没有东西的 而是有上一次你输入的东西  就很难受  必须用一个memset 全部复制为'\0'然后在操作  这个Bug真的是恶心人~~

其实也是自己没注意初始化这种东西 还是需要注意一下的~~

其实还有很多能改进时间复杂度的地方 比如在枚举新字符串的时候可以在原串的基础上做迭代  不必要多余的 字符串替换  还比如 判重的地方用二分写 

甚至看到大神树上dfs  等我学会了 我也贴一发树上深搜的写法  真的是炫酷~~


/**************************************************************
    Problem: 1819
    User: Tdyh
    Language: C++
    Result: Accepted
    Time:2396 ms
    Memory:24464 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
const int N = 210000;
 
int tree[N][26] , cnt, ans[N], cnt_ans, idx[N];
bool nums[N];
 
void Insert(char *str)//建树
{
    int i = 0, k = 0;
    while (str[i]) {
        int pos = str[i++] - 'a';
        if (tree[k][pos] == 0) 
            tree[k][pos] = cnt ++;
        k = tree[k][pos];
    }
//  printf("%d\n",k);
    nums[k] = true;
    return ;
}
 
bool Find(char *str)//判断是否存在
{
    int i = 0, k = 0;
    while (str[i]) {
        int pos = str[i++] - 'a';
        if (tree[k][pos] == 0)
            return false;
        k = tree[k][pos];
    }
    if (nums[k])return true;
    else return false;
}
int find_int(char *str)//查看str的编号是多少
{   
    int i  = 0, k = 0;
    while (str[i]) {
        int pos = str[i++] - 'a';
        if (tree[k][pos] == 0)
            return 0;
        k = tree[k][pos];
    }
    return k;
}
 
void Delete(char *str, char *tar, int pos)
{
    int length_str = strlen(str), p = 0;
    for (int i = 0; i < pos; i ++) 
        tar[p++] = str[i];
    for (int i = pos + 1; i < length_str; i ++)
        tar[p++] = str[i];
}
 
void add(char *str, char *tar, int pos , char op)
{
    int length_str = strlen(str), p = 0;
    for (int i = 0; i < pos; i ++) 
        tar[p++] = str[i];
    tar[p++] = op;
    for (int i = pos ; i < length_str; i ++)
        tar[p++] = str[i];
}
 
void Replace(char *str , char *tar, int pos, char op)
{
    int length_str = strlen(str) , p = 0;
/*  for (int i = 0; i < pos; i ++) 
        tar[p++] = str[i];
    tar[p++] = op;
    for (int i = pos + 1; i < length_str; i ++)
        tar[p++] = str[i];*/
    strcpy(tar , str);
    tar[pos] = op;
}
 
bool judge(int x, int limit)
{
    for (int i  = 0; i < limit; i ++) 
        if (ans[i] == x)
            return true;
    return false;
}
 
int main()
{
    int n , m ;
    cnt = 1;
    memset(tree , 0, sizeof(tree));
    for (int i = 0; i < N; i ++) {
        nums[i] = false;
        idx[i] = 0;
    }
    scanf("%d%d",&n,&m);
    char str[25], temp[25];
    int cnt_q = 0;
    for (int i = 0; i < n; i ++) {
        scanf("%s",str);
        if(strlen(str) == 1)cnt_q++;
        Insert(str);
    }
    getchar();
    for (int i = 0; i < m; i ++) {
        gets(str);
        if (str[0] == '\n') {
            cout << cnt_q << endl;continue;//判断空串的情况 但是不加也能过
        }
        if (Find(str)) {
            printf("-1\n");
        } else {
            int Count = 0, cnt_ans = 0;
            int length_str = strlen(str);
            int id = find_int(str);
            //The part of delete
            if(length_str > 1)
            for (int i = 0; i < length_str; i ++) {
                char tmep[25];
                memset(temp , '\0',sizeof(temp));//这句话非常重要~~~
                Delete(str, temp, i);
            //  printf("delete part of temp == %s\n",temp);
                int temp_id = find_int(temp);
                if(nums[temp_id] && !judge(temp_id , cnt_ans) && temp_id) {
                //  printf("%s\n",temp);
                    Count++;
                    ans[cnt_ans++] = temp_id;
                }
            }
        //  cout << endl;
            //The part of add
            for (int i = 0; i <= length_str; i ++) {
                for (int j = 0; j < 26; j ++) {
                    char temp[25];  
                    memset(temp , '\0',sizeof(temp));
                    add(str , temp, i , 'a' + j);
                //  printf("add part temp == %s\n",temp);
                    int temp_id = find_int(temp);
                    if(nums[temp_id] && !judge(temp_id , cnt_ans) && temp_id) { //  printf("%s\n",temp);
                        Count++;
                        ans[cnt_ans++] = temp_id;
                    }
                }
            }
        //  cout << endl;
            //The part of Replace
            for (int i = 0 ; i < length_str; i ++) {
                for (int j = 0 ; j < 26; j ++) {
                    char temp[25];
                    memset(temp , '\0',sizeof(temp));
                    Replace(str , temp , i , 'a' + j);
            //      printf("%s\n",temp);
                    int temp_id = find_int(temp);
                    if(nums[temp_id] && !judge(temp_id , cnt_ans) && temp_id) {//   printf("%s\n",temp);
                        Count++;
                        ans[cnt_ans++] = temp_id;
                    }
                }
            }
            printf("%d\n",Count);
             
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值