这两种算法比较?

时间:2018-08-21 07:39:49

标签: java algorithm

所以我遇到了一个问题。 “确定字符串是否包含所有唯一字符”

所以我写了这个解决方案,将每个字符添加到集合中,但是如果该字符已经存在,则返回false。

private static boolean allUniqueCharacters(String s) {

    Set<Character> charSet = new HashSet<Character>();
    for (int i = 0; i < s.length(); i++) {
        char currentChar = s.charAt(i);
        if (!charSet.contains(currentChar)) {
            charSet.add(currentChar);

        } else {
            return false;
        }

    }
    return true;

}

根据我正在阅读的书,这是“最佳解决方案”

public static boolean isUniqueChars2(String str) {
    if (str.length() > 128)
        return false;

    boolean[] char_set = new boolean[128];

    for (int i = 0; i < str.length(); i++) {
        int val = str.charAt(i);

        if (char_set[val]) {
            return false;
        }
        char_set[val] = true;
    }

    return true;
}

我的问题是,我的实现是否比所介绍的慢?我以为是这样,但是如果Hash查找为O(1),它们的复杂度是否相同?

谢谢。

6 个答案:

答案 0 :(得分:12)

正如Amadan在评论中所说,这两个解决方案具有相同的时间复杂度O(n),因为您有一个遍历字符串的for循环,并且在for循环中进行了恒定时间的操作。这意味着运行方法所花费的时间随着字符串的长度线性增加。

请注意,时间复杂度完全取决于更改输入大小时所需的时间。这与大小相同的数据有多快无关。

对于相同的字符串,“最优”解决方案应该更快,因为集合在数组上会有一些开销。处理数组比处理集合要快。但是,要使“最佳”解决方案真正起作用,您将需要一个长度为2 ^ 16的数组。那就是有多少个不同的char值。您还需要删除长度大于128的字符串的支票。

这是在时间和空间之间进行权衡的众多示例之一。如果您希望它运行得更快,则需要更多空间。如果要节省空间,则必须变慢。

答案 1 :(得分:3)

这两种算法的O(N)复杂度时间。不同之处在于它们的空间复杂度。

这本书的解决方案将始终需要存储128个字符-O(1),而您解决方案的空间要求将根据输入-O(N)线性变化。

这本书的空间要求基于假定的128个字符集。但是,考虑到可能需要不同的字符集,这可能会很成问题(并且无法扩展)。

答案 2 :(得分:2)

从理论上讲,哈希表是可以接受的,但这是浪费。

哈希图是基于数组构建的(因此它肯定比数组昂贵),并且冲突解决方案需要额外的空间(至少是元素数量的两倍)。此外,任何访问都需要计算哈希值,并可能需要解决冲突。

与直线阵列相比,这在空间和时间方面增加了很多开销。

还要注意,哈希表具有O(1)行为是一种民间传说。最坏的情况是差得多,对于大小为N的表,访问最多需要O(N)时间。


最后,该算法的时间复杂度为O(1),因为当N> 128时,您得出的结论是错误的。

答案 3 :(得分:1)

您的算法也是O(1)。您可以考虑像how my algorithm will react to the change in amount of elements processed这样的复杂性。因此O(n)O(2n)实际上相等。

人们谈论O表示增长率here

答案 4 :(得分:1)

您的解决方案的确可能比本书的解决方案要慢。首先,哈希查找理想地具有恒定的时间查找。但是,如果存在多个哈希冲突,则不会检索对象。其次,即使是恒定时间查找,与按索引查找数组中的元素相比,执行哈希码功能通常也涉及大量开销。这就是为什么您可能要进行数组查找的原因。但是,如果您开始处理非ASCII Unicode字符,则由于大量的空间开销,您可能不希望使用数组方法。

答案 5 :(得分:0)

实现的瓶颈在于,集合的查找(和插入)复杂度*为java -jar myJarName.jar,而数组的查找复杂度为O(log k)

听起来您的算法肯定要差得多。但实际上并非如此,因为O(1)k的限制(否则,参考实现将是错误的,并且会产生越界错误),并且可以将其视为常量。这使得集合查找128的常量也比数组查找大。

O(1)假定一个合理的实现为树或哈希图。哈希图的时间复杂度通常不是恒定,因为填充它需要*调整大小操作,以避免冲突的增加,这会导致线性查找时间,请参见herehere获取有关堆栈溢出的答案。

This article甚至解释说Java 8本身在其查找时间退化为{{1之前,就将哈希图转换为二叉树(用于会话,使用log(n)进行查找)。 }},因为碰撞太多。