动态规划算法的时空复杂度

时间:2016-11-09 00:59:15

标签: algorithm dynamic-programming memoization

此算法来自Cracking the Coding Interview,第5版,在此处找到:https://www.geekbooks.me/book/view/cracking-the-coding-interview-5th-edition

一个孩子正在爬楼梯,有n个台阶,可以跳1步,2步或者 一次3个步骤。实现一种方法来计算孩子的可能方式 可以跑上楼梯。 算法:

 public static int countWaysDP(int n, int[] map) {
    if (n < 0) {
        return 0;
    } else if (n == 0) {
        return 1;
    } else if (map[n] > -1) {
        return map[n];
    } else {
        map[n] = countWaysDP(n - 1, map) + 
                 countWaysDP(n - 2, map) + 
                 countWaysDP(n - 3, map);
        return map[n];
        }
}

此算法的时间和空间复杂度是多少?我认为,由于使用了memoization,因此存储结果,因此不会像纯递归方法那样多次计算值。由于有三次调用countWaysDP,因此时间复杂度为O(3n),它是O(n)的元素。对于map的大小,空间复杂度将是O(n + n)一n,对于递归调用栈,空间复杂度将是n,其也是O(n)的元素。我的推理是否正确?

由于

3 个答案:

答案 0 :(得分:3)

让我们执行代码:

注意递归堆栈的表示法。 1.2.3。表示第二次递归的第三次递归 countWaysDP(n-5) countWaysDP(n -2 countWaysDP(n )。

Consider n=6

1. countWaysDP(6)
1.1. countWaysDP(5)
1.1.1. countWaysDP(4)
1.1.1.1. countWaysDP(3)
1.1.1.1.1. countWaysDP(2)
1.1.1.1.1.1. countWaysDP(1)

1.1.1.1.1.1.1. countWaysDP(0) //returns 1
1.1.1.1.1.1.2. countWaysDP(-1) //returns 0
1.1.1.1.1.1.3. countWaysDP(-2) //returns 0                        -> map[1] = 1 <-

1.1.1.1.1.2. countWaysDP(0) //return 1
1.1.1.1.1.3. countWaysDP(-1) //return 0                           -> map[2] = 2 <-

1.1.1.1.2. countWaysDP(1) //already claculated, returns map[1]
1.1.1.1.3. countWaysDP(0) //returns 1                             ->map[3] = 4 <-

1.1.1.2. countWaysDP(2) //already present, returns map[2]
1.1.1.3. countWaysDP(1) //already present, returns map[1]         -> map[4] = 7 <-

1.1.2. countWaysDP(3) //already present, returns map[3]
1.1.3. countWaysDP(2) //already present, returns map[2]           -> map[5] = 13 <-

1.2. countWaysDP(4) //already present, returns map[4]
1.3. countWaysDP(3) //already present, returns map[3]             -> map[6] = 24 <-

现在假设involking a method is O(1)操作。此示例的总时间为:

6 + 3 + (2 + 2 + 2 + 2 + 2) = 19

是的,你对 TIME 是正确的。其 3n 作为最左边的递归路径取O(n),然后所有其他调用都是O(2n)。

递归堆栈将采用O(n),因为最大堆栈深度为n + 3 ,并且您的映射将采用O(n)空间。所以是的, SPACE O(n + n)= O(n)

答案 1 :(得分:0)

关于您的算法:虽然您将结果存储在地图中,但您的算法每次都会进行3次递归调用,之后才会将解决方案插入到地图中。这意味着您不会重复使用中间结果。

为了重复使用,您需要从n = 1开始,然后进行迭代,直到达到所需的步数。这样,您可以确保将结果重用于所有较小的步骤:

for (int i = 1; i <= n; i++) {
  int current = map[i-1]; // you can make 1 step
  if (i > 1) 
    current += map[i-2]; // you can make 2 steps
  if (i > 2)
    current += map[i-3]; // you can make 3 steps
  map[i] = current;
}
return map[n];

现在的复杂性:

我们使用一个最终有n个条目的地图。因此空间复杂度为O(n)。

我们从1迭代一次到n进行计算。因此时间复杂度也是O(n)。

答案 2 :(得分:0)

使用memoization(O(N)时间复杂度和空间复杂度)的简单解决方案

public static int countWaysDP(int n, int[] map) {
    map[1] = 1; // when n = 1, answer is 1
    map[2] = 2; // when n = 2, answer is 2, (1+1) and (2)
    map[3] = 4; // (1+1+1), (1+2), (2+1), (3)

    for(int i = 4;i <= n; i++)
    {
        map[i] = map[i-1] + map[i-2] + map[i-3]; 
    }

    return map[n];
}

希望这有帮助!!!