Algorithm 动态规划:对还是错

Algorithm 动态规划:对还是错,algorithm,dynamic-programming,Algorithm,Dynamic Programming,我对动态规划有一个概念上的疑问: In a dynamic programming solution, the space requirement is always at least as big as the number of unique sub problems. 我用斐波那契数来表示: f(n) = f(n-1) + f(n-2) 这里有两个子问题,如果输入为n,则所需的空间至少为O(n)。 对吧? 但是,答案是错误的 有人能解释一下吗?答案确实是错的 例如,在斐波那契数列中,您

我对动态规划有一个概念上的疑问:

In a dynamic programming solution, the space requirement is always at least as big as the number of unique sub problems.
我用斐波那契数来表示:

f(n) = f(n-1) + f(n-2)
这里有两个子问题,如果输入为n,则所需的空间至少为O(n)。 对吧?

但是,答案是错误的


有人能解释一下吗?

答案确实是错的

例如,在斐波那契数列中,您可以使用O(1)空间的动态规划,只记住最后两个数字:

fib(n):
   prev = current = 1
   i = 2
   while i < n:
      next = prev + current
      prev = current
      current = next
   return current
fib(n):
上一个=当前=1
i=2
而i

这是一种常见的做法,您不需要所有较小的子问题来解决较大的子问题,您可以丢弃大部分子问题并节省一些空间。

答案确实是错误的

例如,在斐波那契数列中,您可以使用O(1)空间的动态规划,只记住最后两个数字:

fib(n):
   prev = current = 1
   i = 2
   while i < n:
      next = prev + current
      prev = current
      current = next
   return current
fib(n):
上一个=当前=1
i=2
而i

这是一种常见的做法,您不需要所有较小的子问题来解决较大的子问题,您可以放弃其中的大部分并节省一些空间。

如果您使用自下而上的DP实现斐波那契计算,您可以放弃不需要的早期结果。这是一个例子:

fib = [0, 1]
for i in xrange(n):
    fib = [fib[1], fib[0] + fib[1]]
print fib[1]

如本例所示,您只需要记住数组中的最后两个元素。

如果您使用自下而上的DP实现斐波那契计算,您可以放弃不需要的早期结果。这是一个例子:

fib = [0, 1]
for i in xrange(n):
    fib = [fib[1], fib[0] + fib[1]]
print fib[1]

如本例所示,您只需记住数组中的最后两个元素。

此语句不正确。但这几乎是正确的

通常动态规划解需要
O(子问题数)
空间。换句话说,如果有一个问题的动态规划解决方案,它可以使用
O(子问题的数量)
内存来实现

在您的特定问题“斐波那契数的计算”中,如果您写下简单的动态规划解决方案:

Integer F(Integer n) {
  if (n == 0 || n == 1) return 1;
  if (memorized[n]) return memorized_value[n];
  memorized_value[n] = F(n - 1) + F(n - 2);
  memorized[n] = true;
  return memorized_value[n];
}
它将使用
O(子问题数)
内存。但正如您所提到的,通过分析重复性,您可以找到一个使用
O(1)
内存的更优化的解决方案


另外,你提到的斐波那契数的递归有
n+1
子问题。通常通过子问题,人们指的是计算特定
f
值所需的所有
f
值。这里您需要计算
f(0),f(1),f(2),…,f(n)
才能计算
f(n)

此语句不正确。但这几乎是正确的

通常动态规划解需要
O(子问题数)
空间。换句话说,如果有一个问题的动态规划解决方案,它可以使用
O(子问题的数量)
内存来实现

在您的特定问题“斐波那契数的计算”中,如果您写下简单的动态规划解决方案:

Integer F(Integer n) {
  if (n == 0 || n == 1) return 1;
  if (memorized[n]) return memorized_value[n];
  memorized_value[n] = F(n - 1) + F(n - 2);
  memorized[n] = true;
  return memorized_value[n];
}
它将使用
O(子问题数)
内存。但正如您所提到的,通过分析重复性,您可以找到一个使用
O(1)
内存的更优化的解决方案


另外,你提到的斐波那契数的递归有
n+1
子问题。通常通过子问题,人们指的是计算特定
f
值所需的所有
f
值。这里您需要计算
f(0),f(1),f(2),…,f(n)
为了计算
f(n)

并不是所有的动态规划问题都需要使用额外的空间,并且任何自上而下的记忆都可以转换为自下而上,以防止堆栈溢出。@C.B.最坏情况下,从大O表示法来看,自下而上/自上而下不会改变空间复杂性。并非所有动态编程问题都需要使用额外的空间,任何自上而下的记忆都可以转换为自下而上,以防止堆栈溢出。@C.B.最坏情况下,按大O表示法计算,自下而上/自上而下不会改变空间复杂性。对或错:如果动态编程解决方案设置正确,即递推方程正确且每个唯一子问题只求解一次(记忆),则生成的算法将始终在多项式时间内找到最优解。?对或错:如果动态规划解决方案设置正确,即递推方程正确且每个唯一子问题只解一次(记忆化),则生成的算法将始终在多项式时间内找到最优解。?