我无法理解下面的解决函数究竟发生了什么。我知道它做了什么,但是我仍然不清楚 - 我无法想象它,或只是让自己理解它。有人可以解释一下吗?
原始问题陈述(link):
你可以用多少种方法用2x1多米诺骨牌拼成3xn矩形?
这是一个3x12矩形的样本平铺。
代码(取自here):
#include <stdio.h>
int dp[32];
int solve(int n)
{
if(dp[n]!=-1)
return dp[n];
else
{
int i;
int res = 3*solve(n-2);
for(i=4;i<=n;i+=2)
res+=2*solve(n-i);
return dp[n]=res;
}
}
int main()
{
int i;
for(i=0;i<32;i+=2)
dp[i]=-1;
for(i=1;i<32;i+=2)
dp[i]=0;
dp[0]=1;
scanf("%d",&i);
while(i!=-1)
{
printf("%d\n",solve(i));
scanf("%d",&i);
}
return 0;
}
另一件事是,这个算法的时间和空间复杂度是多少?由于它是一个递归函数,它可能是O(log N)
,但我也不确定。
答案 0 :(得分:1)
从技术上讲,运行时是O(1),因为输入的大小有一个上限(特别是32)。但是我们假设一分钟问题的大小不超过32,并考虑这个问题。在这种情况下,运行时为O(n 2 )。在进行了一些大小的递归调用之后,任何将来的相同大小的递归调用都会在时间O(1)中运行。这是由于在dp
表中使用了memoization。这意味着我们可以通过总结所有可能的递归调用来计算总运行时间,即填充dp
表所需的时间。
在大小为n的调用中,完成O(n)工作以填充数组。你可以通过从4开始的for循环来看到这个,并且在每个执行O(1)工作的点上向上计数n到2。由于递归调用的大小为0,1,2,...,n,因此我们有O(n)个调用O(n)调用,每个调用总共为O(n 2 )工作
希望这有帮助!