算法的时间复杂度

时间:2013-01-29 15:40:04

标签: algorithm time-complexity

我想知道以下算法的Big Oh

public List<String> getPermutations(String s){
    if(s.length()==1){
        List<String> base = new ArrayList<String>();
        base.add(String.valueOf(s.charAt(0)));
        return base;
    }

    List<String> combos = createPermsForCurrentChar(s.charAt(0),
                                    getPermutations(s.substring(1));

    return combos;
}
 private List<String> createPermsForCurrentChar(char a,List<String> temp){
    List<String> results = new ArrayList<String>();
    for(String tempStr : temp){
        for(int i=0;i<tempStr.length();i++){
            String prefix = tempStr.substring(0, i);


            String suffix = tempStr.substring(i);

            results.add(prefix + a + suffix);
        }


    }
    return results;
}

我认为getPermutations被称为n次,其中n是字符串的长度。 我的理解是 createPermutations是O(l * m),其中l是列表temp的长度,m是temp中每个字符串的长度。

然而,由于我们正在研究最坏情况分析,m&lt; = n和l&lt; = n!。 临时列表的长度在每次递归调用中都会增长,每个字符串中的字符数也会增加。

这是否意味着该算法的时间复杂度为O(n * n!* n)。或者是O(n * n * n)?

2 个答案:

答案 0 :(得分:2)

好吧,我会把它写成答案而不是一长串的评论。

将长度为n的字符串的getPerm的运行时间表示为T(n)。观察getPerm内部,它调用getPerm(字符串长度为n-1),所以很明显

T(n)=T(n-1) + [run time of createPerm]

请注意,createPerm有2个嵌套循环。外循环遍历getperm结果的大小(长度为n-1的字符串),内循环遍历n-1(单个字符串的长度)。 getPerm(长度为n-1的字符串)的结果是T(n-1)个字符串的列表。从此,我们得到了

[run time of createPerm] = (n-1) T(n-1)

将其代入上一个等式给出

T(n) = T(n-1) + (n-1) T(n-1) = n T(n-1)
退出条件下

T(1)= 1。我们可以扩展以找到解决方案(或者,使用Z变换:Can not figure out complexity of this recurrence)。由于它是一个简单的等式,因此扩展速度更快:

 T(n) = n T(n-1)
      = n (n-1) T(n-2)
      = n (n-1) (n-2) T(n-3) ....
      = n (n-1) ... 1
      = n!

所以T(n)= n!

练习:通过归纳证明这一点! :P

这有意义吗?让我们考虑一下。我们正在创建n个字符的排列:http://en.wikipedia.org/wiki/Permutation

编辑:注意T(n)= n!是O(n!)

答案 1 :(得分:1)

我不是最好的组合,但我认为它是O(n ^ 3),其中n是字符串中的字符数。

我的逻辑是这样的:

的次数
getPermutations(String)
调用

与呼叫相关:

createPermsForCurrentChar(s.charAt(0),getPermutations(s.substring(1));

在第一次调用时,你传递了争论(charAt(0),长度为s.length-1的子串),然后(charAt(1),长度为s.length-2的子串)...为O(n)调用。

每次进入createPermsForCurrentChar时,更重要的是List temp中的元素数。

首先,让我们将该函数分析为独立的东西: 假设List<String> temp中有k个元素,它们具有单调递增的长度,用L =当前长度表示,从L = 1开始,以L = k结束。

外部for循环将迭代k次,这很容易。 内部for循环将迭代L次。 我们的复杂度是O(k“L”)。 L是引号,因为它每次都会改变,让我们看看它是什么样的:第一次外循环迭代,内循环执行一次。第二个外循环ieration,内循环执行两次,依此类推,直到内循环执行k次,给出1 + 2 + 3 + 4 + ... k = O(k ^ 2)。

因此createPermsForCurrentChar是O(k ^ 2)复杂度,其中k是List<String> temp中元素的数量(以及temp中最长字符串的大小)。我们现在想知道的是 - 每次通话List<string> temp会有多少元素?

当我们最终在递归中到达基本情况时,我们传递字符串的倒数第二个字符,并将字符串的最后一个字符传递给createPermsForCurrentChar,因此k = 1。它将创建一个长度为O(k)的单个字符串。 这允许下一次执行从堆栈弹出并再次调用createPermsForCurrentChar,这次是k = 2。然后k = 3,k = 4,k = 5等

我们知道由于我们的递归关系,createPermsForCurrentChar被称为O(n)次,因此k最终将= n。 (1 + 2 + 3 + ... + n)= O(n ^ 2)。考虑到createPermsForCurrentChar的复杂性,得到(1 ^ 2 + 2 ^ 2 + 3 ^ 2 + ... n ^ 2)=(1/3)n ^ 3 +(1/2)n ^ 2 +( 1/6)n(来自http://math2.org/math/expansion/power.htm)。

由于我们只关心我们的主导价值,我们可以说算法是O(n ^ 3)。