我可以将任何递归代码转换为递归关系吗?

问题描述

所以我一直在 youtube 上学习动态规划,这里是链接 https://www.youtube.com/watch?v=oBt53YbR9Kk&t=4257s,我在网格旅行者递归部分学习。但我仍然对时间复杂度感到困惑。

例如这个网格旅行者递归方法

int gridTraveler(int m,int n) {
  if (m == 0 || n == 0) {
    return 0;
  }
  if (m == 1 || n == 1) {
    return 1;
  }
  return gridTraveler(m - 1,n) + gridTraveler(m,n - 1);
}

为什么时间复杂度是 O(2^(m+n))?使用递推关系有什么解释吗?

还有这个带有记忆方法的网格旅行者递归:

Map<String,int> memo = {};

int gridTraveler(int m,int n) {
  if (m == 0 || n == 0) {
    return 0;                      
  }
  if (m == 1 && n == 1) {
    return 1;                    
  }
  if (memo.containsKey('${m},${n}')) {
    return memo['${m},${n}'] as int;          
  }

  if (memo.containsKey('${n},${m}')) {
    return memo['${n},${m}'] as int;            
  }
  memo['${m},${n}'] = gridTraveler(m - 1,n - 1);  
    return memo['${m},${n}'] as int;                                   
}                                                                      
           

为什么时间复杂度是 O(m*n)?使用递推关系有什么解释吗?

解决方法

对于网格旅行者递归方法没有记忆方法,如果我们绘制树,它将看起来像那样

enter image description here

这里对于每个节点或状态,将计算两个子节点/状态,直到它们达到基本情况。因此对于 N= m+n,将有 2^N 个节点或状态。所以时间复杂度是 O(2^(N)) 或 O(2^(n+m))

现在,如果我们看这里的树,我们正在计算先前计算的状态的值,因此同一状态的值会计算多次。使用记忆技术,如果我们计算一个状态,我们会保存它的值,并且一旦达到先前计算的状态,我们就会从 DP 表中返回值。所以我们只计算一个状态一次,DP表中可以有m*n个状态。

DP table

所以使用记忆方法的时间复杂度是 O(m*n)