为什么空间复杂度是 o(n! ) 它应该是线性的,因为递归树的深度是 o(n)

问题描述

void permute(String str,int l,int r) { 
    if (l == r) 
        System.out.println(str); 
    else { 
        for (int i = l; i <= r; i++) { 
            str = swap(str,l,i); 
            permute(str,l+1,r); 
            str = swap(str,i); 
        } 
    } 
} 

打印一个排列是递归树的深度需要线性时间复杂度。

解决方法

但是 permutefor 循环内被调用:

  • 第一次调用n次;
  • 第二次调用n-1次(总共 n * (n-1) 次);
  • 下一个递归级别 (n-2) 的 n * (n-1) * (n-2)
  • ...
  • 最后一级 (n!) 一次

,

由于您使用的是 Java 并且 Java String 是不可变的,因此每次调用 permute 时,您都会再构造 2 个新字符串:

str = swap(str,i,l);
...
str = swap(str,l,i);

因此,您构造了与调用 permute 一样多的字符串,然后是 O(n!)。垃圾收集器可能会回收未使用的回收器,但由于您无法真正控制 GC,因此在最坏的情况下不会回收任何东西。

您的空间复杂度与您管理空间的方式有关。

如果你想要线性空间,你必须使用提供可变字符串的 Java StringBuffer

一般来说,打印不计入空间复杂度(参见 does-space-complexity-analysis-usually-include-output-space),因此您的实现使用 O(n!) 空间复杂度的事实是由于您的实现的内部结构(这里是不可变的 {{ 1}} 秒)。

,

要获得“O(n)”空间复杂度,您必须使用可变数组,因为在 Java 中 String不可变对象。

public static String permute(String str) {
    char[] arr = str.toCharArray();
    permute(arr,arr.length - 1);
    return new String(arr);
}

private static void permute(char[] arr,int l,int r) {
    //...
}