水一发trie板子~
先说这个题怎么套上板子
首先我们判断是否有前缀可以边插入边判断
当我们经过了一个完整的字符串(即当前节点到了一个有标记的节点上)
就是有前缀
我们当然也可以无脑先判断一发(比如我这个)
然后无脑插入就是
减少了一定的编程难度
然后我丧心病狂异想天开写了一发动态的trie
指针警告
好处是内存省下来了
当然删除的时间上来说是省不下来了
具体看代码(代码向预警)
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
//字典集合大小
const int Z=10;
struct trie{
//Z个子节点
trie *ch[Z];
//是否存在字符串的标记挂载
bool vst;
}rt,*root=&rt;//根节点
//输入用的字符串
string input;
void insert(string str)
{
if (str.size()<1)return ;//空字符串返回
trie *now=root;//从根节点开始向下插入
for (register int i=0;i<str.size();i++)
{
int num=str[i]-'0';//子节点下标
if (now->ch[num]==NULL)//需要开一个新的节点
{
now->ch[num]=new trie();//纳新
//初始化节点(也可以写到构造函数里
for (register int j=0;j<Z;j++)
{
now->ch[num]->ch[j]=NULL;//设置成空
now->ch[num]->vst=false;//设置不存在当前子节点表示的字符串
}
now=now->ch[num];//向下一个节点移动
}
else now=now->ch[num];//向下一个节点移动
}
now->vst=true;//挂载当前字符串
}
bool find(string str)
{
if (str.size()<1)return true;//空字符串走人
trie *now=root;//从根节点开始
for (register int i=0;i<str.size();i++)
{
int num=str[i]-'0';//下标
//如果存在没有插入的节点,而且没有经过任何一个完整的字符串,
//一定是不存在任何一个字符串与其为前缀关系
if (now->ch[num]==NULL)return false;
else
{
//经过一个完整的字符串,即经过的这个字符串
//是str的前缀
if (now->ch[num]->vst)return true;
now=now->ch[num];//向下一个节点移动
}
}
//存在另一个字符串包含这个字符串
//即有另一个字符串使得这个字符串是其前缀
return true;
}
//无脑删除,回收空间
void dfs(trie *now)
{
for (register int i=0;i<10;i++)
{
if (now->ch[i]!=NULL)
dfs(now->ch[i]);
}
if (now!=root)delete now;
}
//重新建树
void build()
{
dfs(root);
for (register int i=0;i<10;i++)
{
root->ch[i]=NULL;
}
root->vst=false;
}
int main()
{
int T,n;
cin>>T;
while (T--)
{
bool flag=false;
//先重新建空树
build();
cin>>n;
while (n--)
{
cin>>input;
//只要是存在前缀关系就行
flag=find(input)||flag;
insert(input);
}
//存在即NO
puts(flag?"NO":"YES");
}
return 0;
}