输入: n = 3 输出: 5 解释: 五种不同的方法如上所示。
示例 2:
输入: n = 1 输出: 1
提示:
1 <= n <= 1000
思路:
题目比较晦涩难懂,大致意思就是用这两种类型的块去填满一个2*n的块,保证每一列,都是被填充的。
这道题使用动态规划的方法,在遍历的过程中,将遍历中的状态存储下来,方便接下来的遍历可以在之前存储的状态基础上得到当前的状态。
这里对于某一列i,其存在四中状态
1.整列为空,记为状态0
2.第一个方格被覆盖,记为状态1
3.第二个方格被覆盖,记为状态2
4.两个方格都被覆盖,记为状态3
我们使用一个数组dp[i][state]来表示用瓷砖将第i列铺成状态state的所有方法
- 如果第i列的状态为0,记第i列为空,这时候和第i-1列为满(状态3)的情况一样,即dp[i][0]=dp[i-1][3].
- 如果第i列的状态为1,想要变成这种状态则有两种情况。
即有dp[i][1]=dp[i-1][0]+dp[i-1][2]
- 如果第i列的状态为2,也存在两种情况。
即dp[i][2]=dp[i-1][0]+dp[i-1][1]
- 如果第i列的状态为3,则存储下面四种情况
综上所述,状态转移方程就列出来了。
考虑到特殊情况
当i=0,考虑第0层的状态时,i-1会越界,因此把第0层作为一个初始化层。从1开始计算。
dp[0][0]=0(没有砖),dp[0][1]=0,dp[0][2]=0(无法铺出这两种形状);dp[0][3]=1,可以竖着铺一个多米诺瓷砖。
最后的结果就是dp[n][3]
代码:
class Solution {
public:
const long long mod= 1e9+7;
int numTilings(int n) {
long long dp[1002][4];
for(int i=0;i<n;i++){
for(int j=0;j<4;j++){
dp[i][j]=0;
}
}
dp[0][3]=1;
for(int i=1;i<=n;i++){
dp[i][0]=(dp[i-1][3])%mod;
dp[i][1]=(dp[i-1][0]+dp[i-1][2])%mod;
dp[i][2]=(dp[i-1][0]+dp[i-1][1])%mod;
dp[i][3]=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2]+dp[i-1][3])%mod;
}
return dp[n][3];
}
};