一 问题描述
给出一个电话号码列表,确定它是否一致,如果没有数字是另一个号码的前缀,则称为一致。假设电话目录列出了这些数字。
紧急 911
爱丽丝 97 625 999
鲍勃 91 12 54 26
在这种情况下,无法呼叫 Bob,因为只要您拨打了 Bob 的电话号码的前三位数字,中心就会将您的呼叫转接到紧急线路。所以这个列表不一致。
二 输入和输出
1 输入
输入的第一行给出一个单一的整数,表示测试用例的数目。每个测试用例开头 N,表示电话号码的数目,在单独的一行,接下来的 N 行,每行一个唯一的电话号码。
2 输出
对每个测试用例,如果列表一致,则输出“YES”,否则输出“NO”。
三 输入和输出样例
1 输入样例
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
2 输出样例
NO
YES
四 分析和设计
1 分析
本问题是前缀判断问题。可以用字典树解决。
2 设计
a 将每个字符串依次插入到字典树中。
b 插入过程中判断两种情况:如果字符串处理完毕,仍不空,说明该串是其它串的前缀;如果遇到单词结束标记,说明其它串是该串的前缀。这两种情况均返回true;
c 如果 ans=true,则输出 NO,否则输出 YES。
需要注意的是,在插入判断的过程中,即使发现不一致,也不可以立即停止,继续读入数据,不插入字典树即可。
五 代码
package com.platform.modules.alg.alglib.poj3630;
public class Poj3630 {
public String output = "";
private int maxn = 1005; // 最多 10000 个字符串,每个字符串最多 10 位
private int maxz = 10; // 不同字符个数,例如数字10,小写字母26
int trie[][];
boolean end[]; // 标识单词结束
int n; // 字符串数
int tot; // 下标
boolean insert(String s) { // 将字符串s插入到字典树中
int len = s.length();
int p = 1;
for (int i = 0; i < len; i++) {
int ch = s.charAt(i) - '0'; // 转换成数字
if (trie[p][ch] == 0)
trie[p][ch] = ++tot; // 记录下标
else if (i == len - 1) // 字符串处理完毕,仍不空,说明该串是其它串的前缀
return true;
p = trie[p][ch];
if (end[p])
return true;
}
end[p] = true; // 标记单词结束
return false;
}
public String cal(String input) {
int T;
boolean ans;
String s;
String[] line = input.split("\n");
T = Integer.parseInt(line[0]);
int count = 1;
while (T-- > 0) {
trie = new int[maxn][maxn];
end = new boolean[maxn];
tot = 1;
ans = false;
n = Integer.parseInt(line[count++]);
for (int i = 1; i <= n; i++) {
s = line[count++];
if (ans)
continue;
if (insert(s)) // 不能立即结束,仍要读取 n 个串
ans = true;
}
if (ans)
output += "NO\n"; // 有前缀输出 NO
else
output += "YES\n";
}
return output;
}
}