【每日一题Day25】LC790多米诺和托米诺平铺 | 状态机DP

简介: 有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 “L” 的托米诺形。两种形状都可以旋转。

多米诺和托米诺平铺【LC790】


You have two types of tiles: a 2 x 1 domino shape and a tromino shape. You may rotate these shapes.


9cbcf3f67ee730b02c6f529680d105c6.jpg


Given an integer n, return the number of ways to tile an 2 x n board. Since the answer may be very large, return it modulo 109 + 7.


In a tiling, every square must be covered by a tile. Two tilings are different if and only if there are two 4-directionally adjacent cells on the board such that exactly one of the tilings has both squares occupied by a tile.


有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 “L” 的托米诺形。两种形状都可以旋转。


9cbcf3f67ee730b02c6f529680d105c6.jpg


给定整数 n ,返回可以平铺 2 x n 的面板的方法的数量。返回对 109 + 7 取模 的值。


平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。


又是没做过的题型


  • 思路:使用状态机DP,定义第i列瓷砖的四种不同状态【未铺满】,第i列瓷砖的状态可由前一列的瓷砖状态得到,最终dp[i][1]即为前i列瓷砖被铺满的方案数


。j=0时,代表第i列未被填充

。j=1时,代表第i列两个方块均被填充

。j=2时,代表第i列上面的方块被填充

。j=3时,代表第i列下面的方块被填充


动态规划实现


1.确定dp数组(dp table)以及下标的含义


dp[i][j]:当前i-1列铺满时,当前第i列状态为j时的方案数


j的取值范围为[0,4)


。j=0时,代表第i列未被填充

。j=1时,代表第i列两个方块均被填充

。j=2时,代表第i列上面的方块被填充

。j=3时,代表第i列下面的方块被填充


2.确定递推公式


。dp[i][0]:前i-1列被填充满,第i列未被填充


  • 只能由dp[i-1][1]转移:在第i-1列竖放2*1的骨牌


dp[i][0] = dp[i-1][0]


。dp[i][1]:前i列均被填充


  • 由dp[i-1][0]转移:在第i-1列和第i列横放1*2的骨牌


  • 由dp[i-1][1]转移:在第i-1列和第i列竖放2*1的骨牌


  • 由dp[i-1][2]转移:横放一块L型骨牌


  • 由dp[i-1][3]转移:横放一块L型骨牌


dp[i][1] =dp[i-1][0]+ dp[i-1][1] + dp[i-1][2] + dp[i-1][3]


。dp[i][2]:前i-1列被填充满、第i列上面的方块被填充


  • 由dp[i-1][0]转移:横放一块L型骨牌


  • 由dp[i-1][3]转移:横放一块L型骨牌


dp[i][2] = dp[i-1][0] + dp[i-1][3]


。dp[i][3]:前i-1列被填充满、第i列下面的方块被填充


  • 由dp[i-1][0]转移:横放一块L型骨牌


  • 由dp[i-1][2]转移:横放一块L型骨牌


dp[i][3] = dp[i-1][0] + dp[i-1][2]


3.dp数组如何初始化


dp[1][0]=1
dp[1][1]=1
dp[1][2]=0
dp[1][3]=0


4.确定遍历顺序


。正序遍历i


5.举例推导dp数组



dp[i][0]
dp[i][1] dp[i][2] dp[i][3]
1 1 1 0 0
2 1 2 1 1
3 2 5 2 2
4 5 11 4 4


  • 代码


class Solution {
    public int numTilings(int n) {
        int MOD = (int)1e9 + 7;
        int[][] dp = new int[n+1][4];
        dp[1][0] = 1;
        dp[1][1] = 1;
        for (int i = 2; i <= n; i++){
            dp[i][0] = dp[i-1][1] % MOD;
            for (int j = 0; j < 4; j++){
                dp[i][1] = (dp[i][1] + dp[i-1][j]) % MOD;
            }
            dp[i][2] = (dp[i-1][0] + dp[i-1][3]) % MOD;
            dp[i][3] = (dp[i-1][0] + dp[i-1][2]) % MOD;
        }
        return dp[n][1];
    }
}


。复杂度


  • 时间复杂度:O ( n )


  • 空间复杂度:O ( n )


  • 滚动数组优化


。int a = i & 1


奇数1 偶数0,确定下标


。int b = (i - 1) & 1


奇数0 偶数1


class Solution {
    public int numTilings(int n) {
        int MOD = (int)1e9 + 7;
        int[][] dp = new int[2][4];
        dp[1][0] = 1;
        dp[1][1] = 1;
        for (int i = 2; i <= n; i++){
            int a = i & 1;// 奇数1 偶数0
            int b = (i-1) & 1;// 奇数0 偶数1
            dp[a][0] = dp[b][1];
            int cur = 0;
            for (int j = 0; j < 4; j++){
                cur = (cur + dp[b][j]) % MOD;
            }
            dp[a][1] = cur;
            dp[a][2] = (dp[b][0] + dp[b][3]) % MOD;
            dp[a][3] = (dp[b][0] + dp[b][2]) % MOD;
        }
        return dp[n & 1][1];
    }
}


。复杂度


  • 时间复杂度:O ( n )


  • 空间复杂度:O ( 1 )
目录
相关文章
|
7月前
【每日一题Day312】LC2240买钢笔和铅笔的方案数 | 完全背包 数学
【每日一题Day312】LC2240买钢笔和铅笔的方案数 | 完全背包 数学
63 0
|
7月前
|
人工智能 BI
【每日一题Day267】LC834树中距离之和 | 换根dp
【每日一题Day267】LC834树中距离之和 | 换根dp
50 0
|
7月前
【每日一题Day114】LC1223 掷骰子模拟 | 记忆化搜索+dp
【每日一题Day114】LC1223 掷骰子模拟 | 记忆化搜索+dp
61 0
|
7月前
【每日一题Day366】LC2103环和杆 | 状态压缩
【每日一题Day366】LC2103环和杆 | 状态压缩
54 0
|
7月前
【每日一题Day302】LC849到最近的人的最大距离 | 贪心+分类讨论
【每日一题Day302】LC849到最近的人的最大距离 | 贪心+分类讨论
61 0
|
7月前
力扣 790. 多米诺和托米诺平铺(一维dp)
力扣 790. 多米诺和托米诺平铺(一维dp)
|
7月前
【每日一题Day126】LC1140石子游戏Ⅱ | 博弈dp 记忆化搜索
【每日一题Day126】LC1140石子游戏Ⅱ | 博弈dp 记忆化搜索
56 0
|
7月前
【每日一题Day224】LC2517礼盒的最大甜蜜度 | 二分答案
【每日一题Day224】LC2517礼盒的最大甜蜜度 | 二分答案
35 0
|
7月前
|
图计算
【每日一题Day274】LC42接雨水 | 单调栈
【每日一题Day274】LC42接雨水 | 单调栈
56 0
|
7月前
【每日一题Day262】LC1911最大子序列交替和 | dp
【每日一题Day262】LC1911最大子序列交替和 | dp
40 0