嵌套 For 循环的有效替代方案

Efficient alternative to nested For Loop

我正在做脏话过滤。我嵌套了 2 个 for 循环,如下所示。有没有更好的方法避免嵌套for循环,提高时间复杂度

boolean isProfane = false;
final String phraseInLowerCase = phrase.toLowerCase();
for (int start = 0; start < phraseInLowerCase.length(); start++) {
    if (isProfane) {
        break;
    }
    for (int offset = 1; offset < (phraseInLowerCase.length() - start + 1 ); offset++) {
        String subGeneratedCode = phraseInLowerCase.substring(start, start + offset);
        //BlacklistPhraseSet is a HashSet which contains all profane words
        if (blacklistPhraseSet.contains(subGeneratedCode)) {
            isProfane=true;
            break;
        }
    }
}

如果您想检查连续字符的所有可能组合,那么您的算法是 O(n^2),假设您使用具有 O(1) 查找特征的 Set,例如 HashSet。您可能可以通过将数据和黑名单分解为 Trie 结构并以这种方式遍历每种可能性来减少这种情况。

一种更简单的方法可能是使用像 "profanity always starts and ends at a word boundary" 这样的启发式方法。那么你可以做

isProfane = false;
for(String word: phrase.toLowerCase().split("\s+")) {
    if(blacklistPhraseSet.contains(word)) {
        isProfane = true;
        break;
    }
}

你不会在时间复杂度上提高很多,因为它们在幕后使用迭代,但你可以在空格上拆分短语并迭代短语中的单词数组。 类似于:

String[] arrayWords = phrase.toLowerCase().split(" ");
for(String word:arrayWords){
    if(blacklistPhraseSet.contains(word)){
        isProfane = true;
        break;
    }
}

此代码的问题在于,除非您的单词包含复合词,否则它不会匹配这些词,而据我了解,您的代码会匹配。黑名单中的单词 "f**k" 与我的代码中的 "f**kwit" 不匹配,它会在你的代码中匹配。

考虑Java 8 版本的@Mad Physicist 实现:

        boolean isProfane = Stream.of(phrase.split("\s+"))
            .map(String::toLowerCase)
            .anyMatch(w -> blacklistPhraseSet.contains(w));

        boolean isProfane = Stream.of(phrase
            .toLowerCase()
            .split("\s+"))
            .anyMatch(w -> blacklistPhraseSet.contains(w));