题目大意
有两种形状的瓷砖:一种是 2x1 的多米诺形,另一种是形如 “L” 的托米诺形。两种形状都可以旋转。
XX <- 多米诺
XX <- "L" 托米诺
X
给定 N 的值,有多少种方法可以平铺 2 x N 的面板?返回值 mod 10^9 + 7。
(平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。)
示例:
输入: 3
输出: 5
解释:
下面列出了五种不同的方法,不同字母代表不同瓷砖:
XYZ XXZ XYY XXY XYY
XYZ YYZ XZZ XYY XXY
解题思路
寻找递推公式。
对于任意n来说,要想全部平铺:
- f(n-1)全部平铺的情况下,加上一个2*1的块即可,1种方式;
- f(n-2)全部平铺的情况下,加上两个横着的12块即可,一种方式(注意,这里不能加入两个竖着的21块,因为当n-2完成后,如果加上一个竖着的块,那么n-1也全部平铺完成了,和f(n-1)就重复计算了,因此n-2时仅有一种方式);
- f(n-3)全部平铺的情况下,只能通过放置两个’L’块平铺,两个L块可以上下颠倒,因此有2种方式从f(n-3)平铺成f(n)。注意:如果放置一个21块,则相当于重复计算了f(n-2),如果放置两个12块,则相当于重复计算了f(n-1)。
- 综上所述,我们在通过f(x)平铺f(n)时,x+1~n-1列不能有完成拼好的,否则就重复计算了。
因此:从f(x)平铺f(n)时,我们先放置一个L型块,然后x+1~n-1列全部用12的块填充,这样就会使得每一列都是错位的。填充完毕后,n-1列中有1个格子被填充了,另一个格子空着,同时第n列空着。此时再用另一个L块填充即可。 (对这种方法上下翻转可以形成另一种方案,因此需要2)
递推公式为:f(n)=f(n-1)+f(n-2)+2*(f(n-3)+…+f(0))。 另一方面f(n-1)=f(n-2)+f(n-3)+2*(f(n-4)+…+f(0))。将第二个公式带入第一个公式中,化简得到:f(n)=2*f(n-1)+f(n-3)。
注意:代码中可以仅通过几个变量来完成计算。
class Solution {
public:
int numTilings(int N) {
if (N <= 1)
return 1;
if (N == 2)
return 2;
vector<int> dp(N + 1, 0);
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <=N; ++i)
{
dp[i] = (2 * dp[i - 1] % 1000000007 + dp[i - 3] % 1000000007) % 1000000007;
}
return dp.back();
}
};