这段代码O(R * C)的最坏时间情况如何?

时间:2015-11-10 00:20:39

标签: c++ time-complexity

我在InterviewBit上遇到了这个问题:

int memo[101][101];
int findMinPath(vector<vector<int> > V, int r, int c) {
  int R = V.size();
  int C = V[0].size();
  if (r >= R || c >= C) return 100000000; // Infinity
  if (r == R - 1 && c == C - 1) return 0;
  if (memo[r][c] != -1) return memo[r][c];
  memo[r][c] =  V[r][c] + min(findMinPath(V, r + 1, c), findMinPath(V, r, c + 1));
  return memo[r][c];
}

Callsite : 
memset(memo, -1, sizeof(memo));
findMinPath(V, 0, 0);

假设R = V.size()C = V[0].size()以及V有积极因素

代码是否会创建一个二元树类型的函数调用,它接受O(2 (m + n)),因为每个函数调用都会调用另外两个函数?

3 个答案:

答案 0 :(得分:3)

此算法使用称为dynamic programming的技术。其实质是在查找表中记忆中间结果,并将整体解决方案作为部分解决方案的组合。

在这种特殊情况下,您可以看到findMinPath的每个调用都是一个叶子调用(不是递归),具有恒定的复杂性,或者使memo中的至少一个条目变为非负的。很容易看出,如果memo中的所有条目都是非负数,则该函数将永远不会递归。由于memo中只有 R × C 元素,因此这是整体复杂性的上限。

那就是说,实施相当笨拙。为什么要为memo使用全局变量并依赖于调用者将其初始化为-1?此外,使用memset编写整数数组仅适用于所有字节相同的整数,这会对整数布局产生不可移植的假设。最后,如果 R C 超过魔术值101,则存在缓冲区溢出漏洞。因此,如果您想要迂腐,实际复杂性是不变的。< / p>

答案 1 :(得分:0)

请注意,对于给定的(r,c)

以下代码将不会执行一次以上:

memo [r] [c] = V [r] [c] + min(findMinPath(V,r + 1,c),findMinPath(V,r,c + 1));

一旦设置了备忘[r] [c],功能将返回

如果(memo [r] [c]!= -1)返回备忘录[r] [c];

因此,每个函数最多只能调用1个其他函数。 换句话说,每个函数最终最多执行O(1)次(请注意,您可以在调用站点上转移有关memo [r] [c]!= -1的检查部分)。

O(R * C)可能有(r,c)个组合 因此,函数的时间复杂度为:O(R * C)

答案 2 :(得分:0)

此代码最坏的情况是时间复杂度为O(R*C),因为我们使用自顶向下方法通过将值存储在memo [r] [c]中来实现动态编程,因此仅进行递归调用一次,第二次它将执行以下行

if(memo[r][c] != -1) return memo[r][c],其复杂度为O(1)。

可能的总组合为R*C,因此时间复杂度为O(R*C)