【问题标题】:Understanding Big O notation - Cracking the Coding Interview理解大 O 符号——破解编码面试
【发布时间】:2019-04-13 03:05:24
【问题描述】:

我需要帮助理解作者如何得到大 O 章节中问题 11 的答案。

问题是这样的:

以下代码打印所有长度为 k 的字符串,其中字符按排序顺序排列。它通过生成所有长度为 k 的字符串然后检查每个字符串是否已排序来做到这一点。它的运行时间是多少?

public static int numChars = 26;

public static void printSortedStrings(int remaining) {
    printSortedStrings(remaining, "");
}

public static void printSortedStrings(int remaining, String prefix) {
    if (remaining == 0) {
        if (isInOrder(prefix)) {
            System.out.println(prefix); // Printing the string
        }
    } else {
        for (int i = 0; i < numChars; i++) {
            char c = ithLetter(i);
            printSortedStrings(remaining - 1, prefix + c);
        }
    }
}

public static boolean isInOrder(String s) {
    for (int i = 1; i < s.length(); i++) {
        int prev = ithLetter(s.charAt(i - 1));
        int curr = ithLetter(s.charAt(i));
        if (prev > curr) {
            return false;
        }
    }
    return true;
}

public static char ithLetter(int i) {
    return (char) (((int) 'a') + i);
}

public static void main(String[] args) {
    printSortedStrings(2);
}

书答案:

O(kck),其中 k 是字符串的长度,c 是字母表中的字符数。生成每个字符串需要 O(ck) 时间。然后,我们需要检查它们中的每一个是否已排序,这需要 O(k) 时间。

请注意,上面的答案没有考虑打印字符串,但我在其他问题中看到了相反的情况。

你什么时候考虑在运行时打印字符串?

这是正确的答案吗O(k2ck)?

此外,任何关于能够快速判断此代码​​的运行时存在指数部分的建议将不胜感激。 :)

【问题讨论】:

  • 你如何到达 O(k2ck) ? “2”来自哪里(教科书只有 O(k ck) )。
  • 如果您想考虑打印字符串,那么找到的每个答案都是 O(k)。所以你可以把它算作“检查”的一部分(对于每个候选者来说已经是 O(k))并且它不会增加复杂性。
  • 为什么字符串连接prefix + c不会影响复杂度?我的理解是它本身有O(n)。我错过了什么?
  • 字符串连接的复杂性在最终的k 因素中得到了说明。我认为这会更糟,因为它是在每次通话时完成的,而不是只在最后完成,但通话总数与最后的通话次数成正比,所以没有区别。

标签: java algorithm sorting big-o


【解决方案1】:

简而言之,不。正确答案是 O(kck),如书中所述。

在您检查一个字符串以检查其字符是否已排序后,这将花费 O(k),打印它只会增加 O(k) - 这不会改变您的复杂性。

假设测试一个字符串是否有序需要a*k 操作,打印它需要b*k。那么每个字符串的操作总数最多为(a+b)*k,仍然是O(k)。

编辑:关于问题的第二部分,遍历所有固定长度的单词会导致运行时复杂度呈指数增长,因为有 ck 个这样的单词其中c 是字母的大小,k 是单词的长度。

【讨论】:

  • 我想我现在明白了。每次执行isInOrder 后都会(最多)打印字符串,这就是为什么它不是 O(k*k) 而是 O(k + k) 的原因。 O(k + k) 变为 O(2k),但我们放弃了常数。我对么?我的逻辑有道理吗?
  • 太棒了!感谢您的帮助并回答了我的问题的第二部分。
【解决方案2】:

一般来说,打印一个恒定长度的字符串也被认为是恒定的,但是如果我们想要更精确,让我们将单个字符的打印视为基本操作:这意味着要打印一个 k 长度的字符串,我们有 @987654321 @。

因为我们有 O(ck) 个可能的字符串,对于每个字符串,我们必须检查它是否已排序(使用 O(k))并打印它们(另一个 O(k) ),总复杂度变为 O(ck(k + k)) = O(2ckk)。

但是将一个函数乘以一个常数因子并不会改变它的复杂性,因此答案仍然是 O(ckk)。

【讨论】:

    【解决方案3】:

    打印字符串只是对k 时间的额外补充。

    检查每个字符串是否已排序是O(k),并说打印它是O(dk),对于某个整数d(一个常量)。将两者相加得到O(k + dk),可以重写为O(k(1 + d))。因为这只是我们知道O(k + dk) = O(k) 的一个标量,所以答案不会改变。

    【讨论】:

      猜你喜欢
      • 2018-11-21
      • 1970-01-01
      • 2013-09-05
      • 2015-12-06
      • 2015-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多