Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 86ed730

Browse files
✨feat: add 790
1 parent 6f66bc6 commit 86ed730

File tree

2 files changed

+205
-0
lines changed

2 files changed

+205
-0
lines changed

‎Index/状态机 DP.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
33
| [198. 打家劫舍](https://leetcode.cn/problems/house-robber/) | [LeetCode 题解链接](https://leetcode.cn/problems/house-robber/solution/by-ac_oier-7v1g/) | 中等 | 🤩🤩🤩 |
44
| [552. 学生出勤记录 II](https://leetcode-cn.com/problems/student-attendance-record-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/student-attendance-record-ii/solution/gong-shui-san-xie-yi-ti-san-jie-ji-yi-hu-fdfx/) | 困难 | 🤩🤩🤩🤩 |
5+
| [790. 多米诺和托米诺平铺](https://leetcode.cn/problems/domino-and-tromino-tiling/) | [LeetCode 题解链接](https://leetcode.cn/problems/domino-and-tromino-tiling/solution/gong-shui-san-xie-by-ac_oier-kuv4/) | 中等 | 🤩🤩🤩🤩🤩 |
56
| [801. 使序列递增的最小交换次数](https://leetcode.cn/problems/minimum-swaps-to-make-sequences-increasing/) | [LeetCode 题解链接](https://leetcode.cn/problems/minimum-swaps-to-make-sequences-increasing/solution/by-ac_oier-fjhp/) | 困难 | 🤩🤩🤩🤩🤩 |
67
| [1218. 最长定差子序列](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/solution/gong-shui-san-xie-jie-he-tan-xin-de-zhua-dj1k/) | 中等 | 🤩🤩🤩🤩🤩 |
78
| [剑指 Offer II 091. 粉刷房子](https://leetcode.cn/problems/JEj789/) | [LeetCode 题解链接](https://leetcode.cn/problems/JEj789/solution/by-ac_oier-6v2v/) | 中等 | 🤩🤩🤩🤩🤩 |
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[790. 多米诺和托米诺平铺](https://leetcode.cn/problems/domino-and-tromino-tiling/solution/gong-shui-san-xie-by-ac_oier-kuv4/)** ,难度为 **中等**
4+
5+
Tag : 「状态机 DP」
6+
7+
8+
9+
有两种形状的瓷砖:一种是 `2 x 1` 的多米诺形,另一种是形如 `"L"` 的托米诺形。两种形状都可以旋转。
10+
11+
![](https://assets.leetcode.com/uploads/2021/07/15/lc-domino.jpg)
12+
13+
给定整数 `n` ,返回可以平铺 `2 x n` 的面板的方法的数量。返回对 10ドル^9 + 7$ 取模 的值。
14+
15+
平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。
16+
17+
示例 1:
18+
![](https://assets.leetcode.com/uploads/2021/07/15/lc-domino1.jpg)
19+
```
20+
输入: n = 3
21+
22+
输出: 5
23+
24+
解释: 五种不同的方法如上所示。
25+
```
26+
示例 2:
27+
```
28+
输入: n = 1
29+
30+
输出: 1
31+
```
32+
33+
提示:
34+
* 1ドル <= n <= 1000$
35+
36+
---
37+
38+
### 状态机 DP
39+
40+
定义 $f[i][j]$ 为无须考虑前 $i - 1$ 列(含义为前 $i - 1$ 列已铺满),当前第 $i$ 列状态为 $j$ 时的方案数。
41+
42+
其中 $j$ 取值范围为 $[0, 4)$ 分别对应了当前列的填充情况:
43+
44+
![image.png](https://pic.leetcode.cn/1668221823-xIysQK-image.png)
45+
46+
为了方便,我们人为规定列数从 1ドル$ 开始。
47+
48+
由于骨牌只能在 2ドル \times n$ 的棋盘内填充(不能延伸出棋盘两端),因此我们有显而易见的初始化状态:
49+
50+
$$
51+
f[1][0] = f[1][1] = 1
52+
$$
53+
54+
分别对应「第一列不放置任何骨牌」和「第一列竖着放一块 1ドル \times 2$ 骨牌」合法方案。
55+
56+
而 $f[1][2]$ 和 $f[1][3]$ 由于没法在棋盘左侧以外的位置放置骨牌,不存在合法方案,其值均为 0ドル$。
57+
58+
同时可知 $f[n][1]$ 为我们最终答案,含义为所有列都恰好铺完,不溢出棋盘右侧位置。
59+
60+
61+
不失一般性考虑 $f[i][j]$ 该如何计算,其实就是一个简单的状态机转移分情况讨论:
62+
63+
* $f[i][0]$ : 需要前 $i - 1$ 列铺满,同时第 $i$ 列没有被铺,只能由 $f[i - 1][1]$ 转移而来,即有 $f[i][0] = f[i - 1][1]$
64+
> 这里需要尤其注意:虽然我们能够在上一步留空第 $i - 1$ 列,然后在 $i - 1$ 列竖放一块 1ドル \times 2$ 的骨牌(如下图)
65+
66+
![image.png](https://pic.leetcode.cn/1668224248-NwNCNm-image.png)
67+
68+
> 但我们不能从 $f[i - 1][0]$ 转移到 $f[i][0],ドル因为此时放置的骨牌,仅对第 $i - 1$ 列产生影响,不会对第 $i$ 列产生影响,该决策所产生的方案数,已在 $f[i - 1][X]$ 时被统计
69+
70+
* $f[i][1]$ : 可由 $f[i - 1][j]$ 转移而来(见下图),其中 $j \in [0, 4),ドル即有 $f[i][1] = \sum_{j = 0}^{3} f[i - 1][j]$
71+
72+
![image.png](https://pic.leetcode.cn/1668225376-fiLnws-image.png)
73+
74+
* $f[i][2]$ : 可由 $f[i - 1][0]$ 和 $f[i - 1][3]$ 转移而来
75+
76+
* $f[i][3]$ : 可由 $f[i - 1][0]$ 和 $f[i - 1][2]$ 转移而来
77+
78+
Java 代码:
79+
```Java
80+
class Solution {
81+
int MOD = (int)1e9+7;
82+
public int numTilings(int n) {
83+
int[][] f = new int[n + 10][4];
84+
f[1][0] = f[1][1] = 1;
85+
for (int i = 2; i <= n; i++) {
86+
f[i][0] = f[i - 1][1];
87+
int cur = 0;
88+
for (int j = 0; j < 4; j++) cur = (cur + f[i - 1][j]) % MOD;
89+
f[i][1] = cur;
90+
f[i][2] = (f[i - 1][0] + f[i - 1][3]) % MOD;
91+
f[i][3] = (f[i - 1][0] + f[i - 1][2]) % MOD;
92+
}
93+
return f[n][1];
94+
}
95+
}
96+
```
97+
TypeScript 代码:
98+
```TypeScript
99+
function numTilings(n: number): number {
100+
const MOD = 1e9+7
101+
const f = new Array<Array<number>>()
102+
for (let i = 0; i <= n; i++) f[i] = new Array<number>(4).fill(0)
103+
f[1][0] = f[1][1] = 1
104+
for (let i = 2; i <= n; i++) {
105+
f[i][0] = f[i - 1][1]
106+
let cur = 0
107+
for (let j = 0; j < 4; j++) cur = (cur + f[i - 1][j]) % MOD
108+
f[i][1] = cur
109+
f[i][2] = (f[i - 1][0] + f[i - 1][3]) % MOD
110+
f[i][3] = (f[i - 1][0] + f[i - 1][2]) % MOD
111+
}
112+
return f[n][1]
113+
}
114+
```
115+
Python3 代码:
116+
```Python3
117+
class Solution:
118+
def numTilings(self, n: int) -> int:
119+
f = [[0] * 4 for _ in range(n + 10)]
120+
f[1][0] = f[1][1] = 1
121+
for i in range(2, n + 1):
122+
f[i][0] = f[i - 1][1]
123+
f[i][1] = sum([f[i - 1][j] for j in range(4)])
124+
f[i][2] = f[i - 1][0] + f[i - 1][3]
125+
f[i][3] = f[i - 1][0] + f[i - 1][2]
126+
return f[n][1] % 1000000007
127+
```
128+
* 时间复杂度:$O(n)$
129+
* 空间复杂度:$O(n)$
130+
131+
---
132+
133+
### 滚动数组优化
134+
135+
利用 $f[i][X]$ 仅依赖于 $f[i - 1][X],ドル我们可以采用「滚动数组」方式将其空间优化至 $O(1)$。
136+
137+
Java 代码:
138+
```Java
139+
class Solution {
140+
int MOD = (int)1e9+7;
141+
public int numTilings(int n) {
142+
int[][] f = new int[2][4];
143+
f[1][0] = f[1][1] = 1;
144+
for (int i = 2; i <= n; i++) {
145+
int a = i & 1, b = (i - 1) & 1;
146+
f[a][0] = f[b][1];
147+
int cur = 0;
148+
for (int j = 0; j < 4; j++) cur = (cur + f[b][j]) % MOD;
149+
f[a][1] = cur;
150+
f[a][2] = (f[b][0] + f[b][3]) % MOD;
151+
f[a][3] = (f[b][0] + f[b][2]) % MOD;
152+
}
153+
return f[n & 1][1];
154+
}
155+
}
156+
```
157+
TypeScript 代码:
158+
```TypeScript
159+
function numTilings(n: number): number {
160+
const MOD = 1e9+7
161+
const f = new Array<Array<number>>()
162+
for (let i = 0; i <= 1; i++) f[i] = new Array<number>(4).fill(0)
163+
f[1][0] = f[1][1] = 1
164+
for (let i = 2; i <= n; i++) {
165+
const a = i & 1, b = (i - 1) & 1
166+
f[a][0] = f[b][1]
167+
let cur = 0
168+
for (let j = 0; j < 4; j++) cur = (cur + f[b][j]) % MOD
169+
f[a][1] = cur
170+
f[a][2] = (f[b][0] + f[b][3]) % MOD
171+
f[a][3] = (f[b][0] + f[b][2]) % MOD
172+
}
173+
return f[n & 1][1]
174+
}
175+
```
176+
Python3 代码:
177+
```Python3
178+
class Solution:
179+
def numTilings(self, n: int) -> int:
180+
f = [[0] * 4 for _ in range(2)]
181+
f[1][0] = f[1][1] = 1
182+
for i in range(2, n + 1):
183+
a, b = i & 1, (i - 1) & 1
184+
f[a][0] = f[b][1]
185+
f[a][1] = sum([f[b][j] for j in range(4)])
186+
f[a][2] = f[b][0] + f[b][3]
187+
f[a][3] = f[b][0] + f[b][2]
188+
return f[n & 1][1] % 1000000007
189+
```
190+
* 时间复杂度:$O(n)$
191+
* 空间复杂度:$O(1)$
192+
193+
---
194+
195+
### 最后
196+
197+
这是我们「刷穿 LeetCode」系列文章的第 `No.790` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
198+
199+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
200+
201+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
202+
203+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
204+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /