繁体   English   中英

计算字符串的所有排列(破解编码访谈,第六章 - 示例 12)

[英]Counting all permutations of a string (Cracking the Coding Interview, Chapter VI - Example 12)

在 Gayle Laakman 的书“Cracking the Coding Interview”,第六章(Big O),示例 12 中,问题指出,给定以下用于计算字符串排列的 Java 代码,需要计算代码的复杂度

public static void permutation(String str) {
    permutation(str, "");
}

public static void permutation(String str, String prefix) {
    if (str.length() == 0) {
        System.out.println(prefix);
    } else {
        for (int i = 0; i < str.length(); i++) {
            String rem = str.substring(0, i) + str.substring(i + 1);
            permutation(rem, prefix + str.charAt(i));
        }
    }
}

本书假设既然会有 n! 排列,如果我们将每个排列视为调用树中的一个叶子,其中每个叶子都附加到长度为 n 的路径上,那么将不再有 n*n! 树中的节点(即:调用次数不超过 n*n!)。

但节点数不应该是:

foo+bar

因为调用的数量等于节点的数量(看看视频Permutations Of String | Code Tutorial by Quinston Pimenta 中的图)。

如果我们按照这个方法,节点的数量将是 1(对于树的第一层/根)+ 3(对于第二层)+ 3*2(对于第三层)+ 3*2*1(对于第四层/底层)

即:节点数 = 3!/3! + 3!/2! + 3!/1! + 3!/0! = 16

但是,根据上述方法,节点数将是3*3! = 18

我们不应该把树中的共享节点算作一个节点,因为它们表达了一个函数调用吗?

你是对的节点数量。 该公式给出了确切的数字,但书中的方法计算了多次。

您的总和似乎也接近e * n! 对于大n ,因此可以简化为O(n!)

说调用次数不超过n * n!在技​​术上仍然是正确的n * n! ,因为这是一个有效的上限。 根据如何使用它,这可能没问题,并且可能更容易证明。

对于时间复杂度,我们需要乘以每个节点完成的平均工作。

首先,检查字符串连接。 每次迭代都会创建2新字符串以传递给下一个节点。 一个 String 的长度增加1 ,另一个的长度减少1 ,但总长度始终为n ,每次迭代的时间复杂度为O(n)

每个级别的迭代次数都不同,因此我们不能只乘以n 而是查看整个树的迭代总数,并获得每个节点的平均值。 n = 3

  • 第一层的1节点迭代3次: 1 * 3 = 3
  • 第二层的3节点迭代2次: 3 * 2 = 6
  • 第三层的6节点迭代1次: 6 * 1 = 6

总迭代次数为: 3 + 6 + 6 = 15 这与树中的节点数大致相同。 所以每个节点的平均迭代次数是恒定的。

总的来说,我们有O(n!)次迭代,每次都做O(n)工作,总时间复杂度为O(n * n!)

根据您的视频,我们有 3 个字符( ABC )的字符串,排列数为6 = 3! ,而6恰好等于1 + 2 + 3 但是,如果我们有一个包含 4 个字符 ( ABCD ) 的字符串,则排列数应该是4 * 3! 因为D可以在 1 到 4 之间的任何位置。对于D每个位置,您可以生成3! 其余的排列。 如果您重新绘制树并计算排列的数量,您将看到差异。

根据你的代码,我们有n! = str.length()! n! = str.length()! 排列,但在排列的每次调用中,您还运行从 0 到 n-1 的循环。 因此,您有O(n * n!)


更新以回应已编辑的问题

首先,在编程中,我们经常有0->n-11->n而不是0->n

其次,在这种情况下,我们不计算节点的数量,就像您再次查看剪辑中的递归树一样,您会看到节点重复。 这种情况下的排列应该是彼此唯一的叶子数。

例如,如果您有一个包含 4 个字符的字符串,那么叶子的数量应该是4 * 3! = 24 4 * 3! = 24 ,这将是排列的数量。 但是,在您的代码片段中,每个排列中还有一个0->n-1 = 0->3循环,因此您需要计算循环数。因此,在这种情况下,您的代码复杂度为O(n *n!) = O(4 * 4!)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM