我在接受采访时被问到这个问题, 如果要查明字符串是否仅包含给定的字符集。 例如,让字符串集成为{0,1,2,3,4,5,6,7,8,9}上的所有字符串,即所有“数字”字符串。其中,如果{3,8,5}上的字符串集只是有效字符串,如何检查该字符串是否仅包含有效字符。 说:
Input 8888338385
Output VALID
Input 887837348234
Output : Invalid
我建议的方式是暴力,需要根据无效字符列表检查给定字符串中的每个字符。如果任何一个字符无效,我将跳过检查所有其他字符并显示失败消息。 但是,正如建议here,可能有更好的算法。 请帮忙。
答案 0 :(得分:12)
编辑:感谢Luc Touraille对原始算法的巨大改进。
创建布尔数组a[10]
。对于每个预期数字e
,请设置a[e] = true
。
现在输入中的每个数字d
,检查a[d]
是否为真。如果不是,则返回false。如果它们都成功,则返回true。
您可以将此概括为具有256个元素数组的所有ASCII字符。
如果输入字符串的长度为N,则您的比较字符串为长度M,字母表中的字母数为A,则复杂度为O(N + M)(扫描两个字符串)加O(A )(初始化布尔数组)。因此,除非您的字符串长度接近或大于您的字母大小,否则这可能不是最佳的。
值得指出的是,就Niklas Baumstark的优秀performance comparison而言,我们的两个解决方案实际上是相同的。这里构造的布尔数组与你在双态DFA中构建的转换表相同
答案 1 :(得分:6)
免责声明:根据我的假设,Java似乎suck优化了此处使用的正则表达式,从而导致代码无法使用。即使Javascript的正则表达式似乎比这更快。基准测试还显示尼克的解决方案非常快。
这绝对是正则表达式的任务。在Java中:
public boolean isValidString(String str) {
return str.matches("[358]*");
}
这应该是O(n)
最糟糕的情况,并且不能比这更好,因为每个角色都必须被查看。
如果性能至关重要,您可能希望缓存预编译的模式匹配器:
import java.util.regex.Pattern;
public class Matcher {
private Pattern pattern;
public Matcher() {
this.pattern = Pattern.compile("[358]*");
}
public isValid(String str) {
return pattern.matcher(str).matches();
}
}
答案 2 :(得分:3)
您可以为允许的集合中的每个字符使用地图(如果字母表的范围有限),并直接检查字符串中的每个字符,检查它是否在地图中。这种方式只有O(N),其中N是字符串长度,而不是O(N * M),其中M是允许字符集。如果字母表规模大于另一个数据结构可用于存储允许的字符 - 例如排序树,例如O(N)logN的复杂性。
答案 3 :(得分:3)
对于c或c ++,你可以这样做:
const char* haystack = "8888338385";
const char* filter = "385";
if (strlen(haystack) != strspn(haystack, filter))
{
// oops - haystack contains more characters...
}
c ++(std::string
)
std::string::find_first_not_of
函数
编辑:我知道这是作弊,但问题中没有任何内容可以排除这种情况。
答案 4 :(得分:-2)
我首先会对无效字母的输入和列表进行排序,然后您可以随时确定字符串是否在线性时间内有效