传送门:HihoCoder1014 Trie树
建立字典树,过程中记录每个字母结点走过的次数。
注意:结点数组要开 单词个数*单词长度 大小。因为最坏的情况是每次插入的单词都和已有的单词没有公共前缀。
#include
using namespace std;
const int MAXN = 1e6+5;
int tree[MAXN][26];
int vis[MAXN],node = 1;
char s[MAXN];
void insert(char s[])
{
int len = strlen(s);
int p = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
if (!tree[p][ch]) // 没有结点
{
tree[p][ch] = node++; // 分配一个结点
}
p = tree[p][ch];
vis[p]++; // 统计结点访问次数
}
return ;
}
int search(char s[])
{
int len = strlen(s);
int p = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
if(!tree[p][ch]) // 没有对应结点
{
return 0;
}
p = tree[p][ch];
}
return vis[p];
}
int main()
{
int n;
scanf("%d",&n);
while (n--)
{
scanf("%s",&s);
insert(s);
}
scanf("%d",&n);
while (n--)
{
scanf("%s",&s);
printf("%d\n",search(s));
}
}
传送门:POJ2001 Shortest Prefixes
给定一组单词,找出对于每个单词能唯一(无歧义)标识该单词的最短前缀。
根据给定的一组单词建立字典树,对于每个单词找到第一个不是公共前缀的字母即可。
#include
#include
using namespace std;
const int MAXN = 2e4+5;
int tree[MAXN][26];
int vis[MAXN],node = 1;
char s[MAXN][21];
void insert(char s[])
{
int len = strlen(s);
int p = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
if (!tree[p][ch])
{
tree[p][ch] = node++;
}
p = tree[p][ch];
vis[p]++;
}
return ;
}
void search(char s[])
{
int len = strlen(s);
int p = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
p = tree[p][ch];
putchar(s[i]); // 输出字母,直到不在公共前缀里
// 只访问了一次,说明该字母不在公共前缀里
// 则 公共前缀 + 该字母 能唯一标识该单词
if (vis[p] == 1)
{
return ;
}
}
}
int main()
{
int ind = 0;
while (~scanf("%s",&s[ind]))
{
insert(s[ind]);
ind++;
}
for (int i = 0; i < ind; i++)
{
printf("%s ",s[i]);
search(s[i]);
printf("\n");
}
}
传送门:HDU2072 单词数
这道题主要麻烦在输入是一行,要对其进行单词的提取,而且可能会存在单词间间隔多个空格或末尾是空格的情况。
对于一行中的每个单词,判断是否出现过,如果没出现过,将其加入已出现集合并把个数加一,如果出现过则不作处理。
对于判断是否出现过和加入已出现集合可以采用字典树或者set。
#include
using namespace std;
const int MAXN = 5e4 + 5;
int tree[MAXN][30];
int vis[MAXN*100],node = 1;
void insert(string s)
{
int len = s.size();
int p = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
if (!tree[p][ch])
{
tree[p][ch] = node++;
}
p = tree[p][ch];
}
vis[p] = 1; // 标记结尾
}
bool search(string s)
{
int len = s.size();
int p = 0,cnt = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
if (!tree[p][ch])
{
return 0;
}
p = tree[p][ch];
}
return vis[p];
}
int main()
{
string s,temp;
while (getline(cin,s) && s[0] != '#')
{
int len = s.size(), ans = 0;
temp = "";
// 提取出一行中的每个单词
for (int i = 0; i < len; i++)
{
if(s[i] == ' ')
{
// 单词不为空且字典树中没有
if (temp != "" && !search(temp))
{
ans++;
insert(temp);
temp = ""; // 重置
}
}
else
{
temp += s[i]; // 复制单词
}
}
// 别忘了处理最后一个
if (temp != "" && !search(temp))
{
ans++;
}
cout << ans << "\n";
memset(tree,0,sizeof(tree));
memset(vis,0,sizeof(vis));
node = 1;
}
return 0;
}
#include
using namespace std;
const int MAXN = 5e4 + 5;
set<string> st;
int main()
{
string s,temp;
while (getline(cin,s) && s[0] != '#')
{
stringstream str(s);
while (str >> temp)
{
st.insert(temp);
}
cout << st.size() << "\n";
st.clear();
}
return 0;
}
#include
using namespace std;
const int MAXN = 5e4 + 5;
set<string> st;
char s[MAXN], *p;
int main()
{
while (gets(s) && s[0] != '#')
{
p = strtok(s, " ");
while (p)
{
st.insert(p);
p = strtok(NULL," ");
}
cout << st.size() << "\n";
st.clear();
}
return 0;
}
传送门:HDU1247 Hat’s Words
给定一组单词,若某个单词能由其他两个单词拼接而成,就输出它。
注意:同一个单词用两次,以此拼接成另一个单词也是可以的。
输入
a
aa
输出:
aa
解释:
a + a = aa
先将所有单词存储起来,然后对每个单词进行拆分,判断被拆分的两部分是否是单独的单词。
#include
using namespace std;
const int MAXN = 5e4 + 5;
int tree[MAXN][30];
int vis[MAXN*100],node = 1;
char s[MAXN][100],s1[100],s2[100];;
void insert(char s[])
{
int len = strlen(s);
int p = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
if (!tree[p][ch])
{
tree[p][ch] = node++;
}
p = tree[p][ch];
}
vis[p] = 1; // 标记单词结尾
}
bool search(char s[])
{
int len = strlen(s);
int p = 0,cnt = 0;
for (int i = 0; i < len; i++)
{
int ch = s[i] - 'a';
if (!tree[p][ch])
{
return 0;
}
p = tree[p][ch];
}
return vis[p];
}
int main()
{
int ind = 0;
while (~scanf("%s",&s[ind]))
{
insert(s[ind]);
ind++;
}
for (int i = 0; i < ind; i++)
{
int len = strlen(s[i]);
for (int j = 1; j < len; j++)
{
// 复制全部
strcpy(s1,s[i]);
// 再从 j 位置截断
s1[j] = '\0';
// 复制后一部分
strcpy(s2,s[i] + j);
// 如果两部分都是单独的单词
if (search(s1) && search(s2))
{
printf("%s\n",s[i]);
// 该单词判断结束
break;
}
}
}
return 0;
}
#include
using namespace std;
const int MAXN = 5e4 + 5;
set<string> st;
int main()
{
string s, a, b;
while (cin >> s)
{
st.insert(s);
}
for (auto it : st)
{
int size = it.size();
for (int i = 1; i < size; i++)
{
a = it.substr(0, i);
b = it.substr(i, size - i);
if (st.count(a) && st.count(b))
{
cout << it << "\n";
break;
}
}
}
return 0;
}