在给定字符串中搜索字符集的最快算法

Posted

技术标签:

【中文标题】在给定字符串中搜索字符集的最快算法【英文标题】:Fastest algo for searching set of characters in given string 【发布时间】:2011-02-01 08:25:50 【问题描述】:

这是我和我的一个朋友进行的一场辩论:创建一个验证方法来检查给定字符串是否包含不允许的字符之一的最快方法是什么

方法一:简单

char [] invalidChars = "!@#$%^...".toCharArray();
        for (int i = 0; i < myString.length(); i++) 
            char ch = myString.charAt(i);
            for (int j = 0; j < invalidChars.length; j++) 
                if (invalidChars[j] == ch) 
                    return false;
                
            
        

方法二:利用 Map 的 O(1)

Map <String,String> map = new HashMap<String, String>();
        map.put("!", null);
        map.put("@", null);
        map.put("#", null);
        map.put("$", null);
        map.put("^", null);
        ...
        for (int i = 0; i < labels.length(); i++) 
            char ch = labels.charAt(i);
            if (map.containsKey(ch)) 
                return false;
            
            return true;
        

方法 I 实际上是 N2,但在 invalidChars 数量较少时与 N 一样好。 情况一:无效字符多,情况二:无效字符少时,应该首选什么?

注意:我不是在寻找任何内置的 java 解决方案,而是过滤少数(不是全部)非文本字符的算法

【问题讨论】:

【参考方案1】:

如果您只对验证 ASCII 字符感兴趣,那么长度为 128 的布尔查找表可能比上述任何一种方法都快。

【讨论】:

虽然这可能是一个解决方案,但这并不是问题的真正答案。 @Roy:为什么不是答案?这是一个 O(1) 的“算法”,有一定的限制。 对不起,我看错了,你是对的,我赞成你的评论。我以为他只想知道两者中哪一个更快。 不,我的主要目的不是拒绝所有非ascii字符,而是过滤少数 @taranfx:我知道。这不是我建议的!我建议您可以使用布尔数组,并通过 ASCII 字符值对其进行索引。【参考方案2】:

有一个简单的方法可以为您提供O(n log(m)) 时间复杂度,其中n 是输入的长度,m 是不允许使用的字符数。

一次扫描输入的一个字符,并使用二分搜索在(排序的)不允许的字符数组中查找当前字符。

【讨论】:

【参考方案3】:

如果你使用 HashSet,它在添加时给你 O(1) 并且包含你有:

O(n) 用于插入每个禁止字符 每个比较操作的 O(m)

这导致 O(m+n) 其中 m 是禁止字符的数量,n 是字符串的长度。但我已经看到效果更好的答案。

但请记住,大多数事情都会带来开销(例如 HashSet/HashMap 中的“哈希”)。因此,即使渐近性能可能更好,简单的实现也可能在小输入上更快。我并不是说您应该使用具有 O(n²) 的东西,但对于一组常见的数据,将 O(n log n) 解决方案与 O(m) 解决方案进行比较可能是值得的!

【讨论】:

【参考方案4】:

最快! HashMap 远不是最快的解决方案,只是理论上它是 O(1)。

在 java 中:java.util.BitSet 专为满足您的需求而设计。 或者使用自解包的 long[]/int[] 数组(取决于目标架构 32/64)

为什么 HashMap 不好?访问和创建存储桶带来的额外行李比单独查找要高。

【讨论】:

【参考方案5】:

构建一个 hashmap 并将项目放入其中是相对昂贵的。但是,正如您所说,在哈希图中查找项目是 O(1)。

所以我们有 hashmap fill: O(n log n) with lookup O(1).

或者标准方式(填充O(1)查找O(n))。

但是,由于 O(n) 查找发生在每个字符串中,第一个方法总共是 O(numberOfInvalidChars + strings*NumberofInValidChars),第二个方法是 O(numInv log numInv + strings)。哪个更便宜,所以几乎总是更便宜。

【讨论】:

以上是关于在给定字符串中搜索字符集的最快算法的主要内容,如果未能解决你的问题,请参考以下文章

全文匹配的各种搜索算法和性能

哪种 BouncyCastle API 支持的加密算法对于 C# .NET 中的短字符串加密最快且非常安全?

最快的子串搜索算法是啥?

在字符串集合中搜索的最快方法

Java中最快的子字符串搜索方法是啥

搜索文本中多个字符串之一的有效算法?