LeetCode 题解工作台

多米诺和托米诺平铺

有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 "L" 的托米诺形。两种形状都可以旋转。 给定整数 n ,返回可以平铺 2 x n 的面板的方法的数量。 返回对 10 9 + 7 取模 的值。 平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中…

category

1

题型

code_blocks

6

代码语言

hub

3

相关题

当前训练重点

中等 · 状态·转移·动态规划

bolt

答案摘要

我们首先要读懂题意,题目实际上是让我们求铺满 $2\times n$ 的面板的方案数,其中面板上的每个正方形只能被一个瓷砖覆盖。 瓷砖的形状有两种,分别是 `2 x 1` 型 和 `L` 型,并且两种瓷砖都可以旋转。我们将旋转后的瓷砖分别记为 `1 x 2` 型 和 `L'` 型。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

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

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

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

 

示例 1:

输入: n = 3
输出: 5
解释: 五种不同的方法如上所示。

示例 2:

输入: n = 1
输出: 1

 

提示:

  • 1 <= n <= 1000
lightbulb

解题思路

方法一:动态规划

我们首先要读懂题意,题目实际上是让我们求铺满 2×n2\times n 的面板的方案数,其中面板上的每个正方形只能被一个瓷砖覆盖。

瓷砖的形状有两种,分别是 2 x 1 型 和 L 型,并且两种瓷砖都可以旋转。我们将旋转后的瓷砖分别记为 1 x 2 型 和 L' 型。

我们定义 f[i][j]f[i][j] 表示平铺前 2×i2\times i 的面板,其中 jj 表示最后一列的状态。最后一列有 44 种状态,分别是:

  • 最后一列铺满,记为 00
  • 最后一列只铺了上方一个瓷砖,记为 11
  • 最后一列只铺了下方一个瓷砖,记为 22
  • 最后一列没有铺瓷砖,记为 33

那么答案就是 f[n][0]f[n][0]。初始时 f[0][0]=1f[0][0]=1,其余 f[0][j]=0f[0][j]=0

我们考虑铺到第 ii 列,来看看状态转移方程:

j=0j=0 时,最后一列铺满,可由前一列的 0,1,2,30,1,2,3 四种状态铺上对应的瓷砖转移而来,即 f[i1][0]f[i-1][0] 铺上 1 x 2 型瓷砖,或者 f[i1][1]f[i-1][1] 铺上 L' 型瓷砖,或者 f[i1][2]f[i-1][2] 铺上 L' 型瓷砖,或者 f[i1][3]f[i-1][3] 铺上两块 2 x 1 型瓷砖。因此 f[i][0]=j=03f[i1][j]f[i][0]=\sum_{j=0}^3f[i-1][j]

j=1j=1 时,最后一列只铺了上方一个瓷砖,可由前一列的 2,32,3 两种状态转移而来,即 f[i1][2]f[i-1][2] 铺上 2 x 1 型瓷砖,或者 f[i1][3]f[i-1][3] 铺上 L 型瓷砖。因此 f[i][1]=f[i1][2]+f[i1][3]f[i][1]=f[i-1][2]+f[i-1][3]

j=2j=2 时,最后一列只铺了下方一个瓷砖,可由前一列的 1,31,3 两种状态转移而来,即 f[i1][1]f[i-1][1] 铺上 2 x 1 型瓷砖,或者 f[i1][3]f[i-1][3] 铺上 L' 型瓷砖。因此 f[i][2]=f[i1][1]+f[i1][3]f[i][2]=f[i-1][1]+f[i-1][3]

j=3j=3 时,最后一列没有铺瓷砖,可由前一列的 00 一种状态转移而来。因此 f[i][3]=f[i1][0]f[i][3]=f[i-1][0]

可以发现,状态转移方程中只涉及到前一列的状态,因此我们可以使用滚动数组优化空间复杂度。

注意,过程中的状态数值可能会很大,因此需要对 109+710^9+7 取模。

时间复杂度 O(n)O(n),其中 nn 为面板的列数。空间复杂度 O(1)O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
    def numTilings(self, n: int) -> int:
        f = [1, 0, 0, 0]
        mod = 10**9 + 7
        for i in range(1, n + 1):
            g = [0] * 4
            g[0] = (f[0] + f[1] + f[2] + f[3]) % mod
            g[1] = (f[2] + f[3]) % mod
            g[2] = (f[1] + f[3]) % mod
            g[3] = f[0]
            f = g
        return f[0]
speed

复杂度分析

指标
时间complexity is O(N) since each dp[n] depends on a fixed number of previous states, and space complexity is O(N) for storing all states. Optimizations can reduce space to O(1) by keeping only the last three states.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Look for efficient dynamic programming over naive recursion with exponential blowup.

  • question_mark

    Expect correct handling of partial row states to accommodate L-shaped trominoes.

  • question_mark

    Check whether modulo arithmetic is applied to prevent overflow on large N.

warning

常见陷阱

外企场景
  • error

    Ignoring the partial states caused by trominoes and double-counting configurations.

  • error

    Forgetting to apply modulo 10^9 + 7 at each dp update.

  • error

    Assuming only domino placements without considering rotated tromino contributions.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Tiling a 3xN board with dominoes and trominoes, requiring additional state dimensions.

  • arrow_right_alt

    Counting tilings with forbidden placements or obstacles on the 2xN board.

  • arrow_right_alt

    Tiling with additional tile shapes, increasing the number of states to track.

help

常见问题

外企场景

多米诺和托米诺平铺题解:状态·转移·动态规划 | LeetCode #790 中等