反思:之前在删除单词的时候,只是删除掉单词前缀以后的字符,而没有把整个单词都删除掉,导致WA了很多次。
高手请略过...
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
using namespace std;
struct Dic {
Dic *nt[26];//指向下一个字符的指针
int num;//重叠字符出现的个数
Dic() {
num = 1;//明显,初始化的时候,字符就为1个
for (int i = 0; i < 26; i++)nt[i] = NULL;
}
};
void insert(Dic *root, char *str) {
int len = strlen(str);
int pos;
Dic *p = root;
for (int i = 0; i < len; i++) {
pos = str[i] - 'a';
if (p->nt[pos] == NULL) p->nt[pos] = new Dic;//字典中不存在这个字符,则插入一个新的结点
else p->nt[pos]->num++;//如果该字符存在,则该结点的重叠个数+1
p = p->nt[pos];
}
}
bool search(Dic *root, char *str) {
int len = strlen(str);
int pos;
Dic *p = root;
for (int i = 0; i < len; i++) {
pos = str[i] - 'a';
if (p->nt[pos] == NULL)return false;
p = p->nt[pos];
}
return true;
}
void Del(Dic *root, char *str) {
Dic *pre = NULL, *p = root;
int len = strlen(str);
int pos, sum;
//遍历到前缀的最后一个字符
for (int i = 0; i < len; i++) {
pos = str[i] - 'a';
if (p->nt[pos] == NULL)return;
p = p->nt[pos];
}
sum = p->num;//拥有这个前缀的单词的个数
p = root;
for (int i = 0; i < len; i++) {
pos = str[i] - 'a';
pre = p;//记录前一个结点,方便删除
p = p->nt[pos];
p->num -= sum; //因为要删除“拥有这个前缀单词”,所以就需要在树上减去 “拥有这个前缀的单词的个数”
if (p->num == 0) //如果为0,则表明:拥有这个前缀的单词都不存在了,所以直接赋值为NULL
pre->nt[pos] = NULL;
}
}
int main() {
int N;
Dic *root = new Dic;
cin >> N;
while (N--) {
char order[10], str[31];
scanf("%s %s", order, str);
if (order[0]=='i') {
insert(root, str);
}
else if (order[0] == 'd') {
Del(root, str);
}
else if (order[0] == 's') {
if (search(root, str)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}