我有一个关键字列表,我希望能够找到一个字符串是否包含任何这些关键字。现在我的解决方案需要O(n)。有没有更快的方式进行此搜索而不循环每个关键字并进行比较/包含?
即。 Keywords =“cat”,“hat”,“mat”,“bat”,“fat”,“sat”,“rat”,“pat”,“foo bar”,“foo-bar” String =“盒子里有一只猫。” 结果是正确的,因为“cat”匹配'keywords'中的一个单词
编辑: 当我说O(n)时,我想我不太清楚。我的意思是说O(n)其中n =关键字的数量。
答案 0 :(得分:4)
您可以使用Boyer-Moore,其中涉及预处理字符串,但您无法击败O(KN)的最坏情况,其中K是关键字长度的总和, N是字符串的长度。最好的情况当然是次线性的,但你不能有最坏情况的次线性运行时。
请注意,比较不是免费的。这不像你可以比较O(1)中的两个字符串,看它们是否相等,你必须遍历字符。散列可以让你在恒定时间内与你需要比较的东西,但没有多大帮助,因为两个不同的字符串可以具有相同的散列。这并不是说散列不好,它是,但它并没有改变最坏情况的运行时复杂性。
最后,你需要比较角色,Boyer-Moore提供了一个非常好的方法。当然,如果您使用某种基于散列的构建,您可以在摊销的常量时间内排除某些关键字,但这并不会改变在最坏的情况下(以及许多其他情况),你的事实。需要比较字符。
另请注意,根据我们对数据的假设以及我们如何构建索引结构,可以实现非常好的实际运行时。仅仅因为最坏情况的复杂性不是次线性并不意味着实际的运行时不会非常快。没有单一的简单或正确的解决方案,问题可以通过各种方式来解决。在信息检索方面,解决所有问题从来都不是一个快速而肮脏的答案。
答案 1 :(得分:1)
k = # of chars in sentence
n = # of keywords
m = # of words in sentence
您可以通过散列O(k + n)
中的字词来获得sentence
时间复杂度。
将句子分成单词需要O(k)
。创建HashSet也需要O(k)
。检查哈希n
次需要n*O(1) = O(n)
,因此总时间复杂度为O(k + n)
。
修改1:哈希所有n
个关键字在技术上是n*O(k/m)
,其中k/m
是平均值。字长。但是,k/m
不会根据输入的大小进行缩放,因此它仍会提供O(n)
。
Edit2:仅供参考,Boyer-Moore将匹配任何子字符串,而不仅仅是关键字;例如。 “猫”将匹配“catepillar”。此外,因为它更通用,它的运行时间比简单的单词匹配更差,O(KN)
为@SteveP。在他的回答中。
因此,如果您只需要字匹配,而不是子字符串匹配,请坚持使用上述散列。
答案 2 :(得分:1)
可以尝试使用contains()。
获取字符串;字符串传递=“盒子里有一只猫”;
使用for循环来完成关键词。如果关键字是一个数组。
for(int i = 0; i < keywords.length; i++){
if(passed.toLowerCase().contains(keywords[i]){
//set true;
}else{
//set false;
}
}
无论是循环还是单独检查每个单词,我都不认为你会比O(n)好多了
答案 3 :(得分:0)
不确定它会找到inO(n)。
但找到元素的解决方案可能就像这样
List<String> keywords = new ArrayList<String> (Arrays.asList("cat", "hat", "mat", "bat", "fat", "sat", "rat", "pat", "foo bar", "foo-bar"));
String search= "There is a cat in the box." ;
List<String> searchWords = new ArrayList<String> (Arrays.asList(search.split(" ")));
System.out.println(!Collections.disjoint(keywords,searchWords));
答案 4 :(得分:0)
你可能不会比O(n)更好,因为这件作品有一个线性组件 - 你必须以某种形状,形式或时尚方式拖网。
考虑使用Set
:
public boolean inPhrase(String phrase, String searchWord) {
Set<String> phraseSet = new HashSet<>();
// remove the punctuation and split the words on white space.
for(String s: phrase.replaceAll("[.,?!;"'], "").split(" ")) {
phraseSet.add(s);
}
return phraseSet.contains(searchWord);
}