Skip to content

Commit 0fa1357

Browse files
authored
feat: add solutions to lc problem: No.1411 (doocs#2003)
No.1411.Number of Ways to Paint N \303\227 3 Grid
1 parent 0bf2aab commit 0fa1357

File tree

9 files changed

+681
-62
lines changed

9 files changed

+681
-62
lines changed

solution/1400-1499/1411.Number of Ways to Paint N × 3 Grid/README.md

+317-2
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,27 @@
6767
- 当状态为 $010$ 型时:下一行可能的状态为:$101$, $102$, $121$, $201$, $202$。这 $5$ 个状态可归纳为 $3$ 个 $010$ 型,$2$ 个 $012$ 型。
6868
- 当状态为 $012$ 型时:下一行可能的状态为:$101$, $120$, $121$, $201$。这 $4$ 个状态可归纳为 $2$ 个 $010$ 型,$2$ 个 $012$ 型。
6969

70-
综上所述,可以得到:$newf0 = 3 * f0 + 2 * f1$$newf1 = 2 * f0 + 2 * f1$。
70+
综上所述,可以得到:$newf0 = 3 \times f0 + 2 \times f1$, $newf1 = 2 \times f0 + 2 \times f1$。
7171

72-
时间复杂度 $O(n)$。
72+
时间复杂度 $O(n)$,其中 $n$ 是网格的行数。空间复杂度 $O(1)$。
73+
74+
**方法二:状态压缩 + 动态规划**
75+
76+
我们注意到,网格只有 $3$ 列,那么一行中最多有 $3^3=27$ 种不同的涂色方案。
77+
78+
因此,我们定义 $f[i][j]$ 表示前 $i$ 行中,第 $i$ 行的涂色状态为 $j$ 的方案数。状态 $f[i][j]$ 由 $f[i - 1][k]$ 转移而来,其中 $k$ 是第 $i - 1$ 行的涂色状态,且 $k$ 和 $j$ 满足不同颜色相邻的要求。即:
79+
80+
$$
81+
f[i][j] = \sum_{k \in \text{valid}(j)} f[i - 1][k]
82+
$$
83+
84+
其中 $\text{valid}(j)$ 表示状态 $j$ 的所有合法前驱状态。
85+
86+
最终的答案即为 $f[n][j]$ 的总和,其中 $j$ 是任意合法的状态。
87+
88+
我们注意到,$f[i][j]$ 只和 $f[i - 1][k]$ 有关,因此我们可以使用滚动数组优化空间复杂度。
89+
90+
时间复杂度 $O((m + n) \times 3^{2m})$,空间复杂度 $O(3^m)$。其中 $n$ 和 $m$ 分别是网格的行数和列数。
7391

7492
<!-- tabs:start -->
7593

@@ -89,6 +107,44 @@ class Solution:
89107
return (f0 + f1) % mod
90108
```
91109

110+
```python
111+
class Solution:
112+
def numOfWays(self, n: int) -> int:
113+
def f1(x: int) -> bool:
114+
last = -1
115+
for _ in range(3):
116+
if x % 3 == last:
117+
return False
118+
last = x % 3
119+
x //= 3
120+
return True
121+
122+
def f2(x: int, y: int) -> bool:
123+
for _ in range(3):
124+
if x % 3 == y % 3:
125+
return False
126+
x //= 3
127+
y //= 3
128+
return True
129+
130+
mod = 10**9 + 7
131+
m = 27
132+
valid = {i for i in range(m) if f1(i)}
133+
d = defaultdict(list)
134+
for i in valid:
135+
for j in valid:
136+
if f2(i, j):
137+
d[i].append(j)
138+
f = [int(i in valid) for i in range(m)]
139+
for _ in range(n - 1):
140+
g = [0] * m
141+
for i in valid:
142+
for j in d[i]:
143+
g[j] = (g[j] + f[i]) % mod
144+
f = g
145+
return sum(f) % mod
146+
```
147+
92148
### **Java**
93149

94150
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -109,6 +165,68 @@ class Solution {
109165
}
110166
```
111167

168+
```java
169+
class Solution {
170+
public int numOfWays(int n) {
171+
final int mod = (int) 1e9 + 7;
172+
int m = 27;
173+
Set<Integer> valid = new HashSet<>();
174+
int[] f = new int[m];
175+
for (int i = 0; i < m; ++i) {
176+
if (f1(i)) {
177+
valid.add(i);
178+
f[i] = 1;
179+
}
180+
}
181+
Map<Integer, List<Integer>> d = new HashMap<>();
182+
for (int i : valid) {
183+
for (int j : valid) {
184+
if (f2(i, j)) {
185+
d.computeIfAbsent(i, k -> new ArrayList<>()).add(j);
186+
}
187+
}
188+
}
189+
for (int k = 1; k < n; ++k) {
190+
int[] g = new int[m];
191+
for (int i : valid) {
192+
for (int j : d.getOrDefault(i, List.of())) {
193+
g[j] = (g[j] + f[i]) % mod;
194+
}
195+
}
196+
f = g;
197+
}
198+
int ans = 0;
199+
for (int x : f) {
200+
ans = (ans + x) % mod;
201+
}
202+
return ans;
203+
}
204+
205+
private boolean f1(int x) {
206+
int last = -1;
207+
for (int i = 0; i < 3; ++i) {
208+
if (x % 3 == last) {
209+
return false;
210+
}
211+
last = x % 3;
212+
x /= 3;
213+
}
214+
return true;
215+
}
216+
217+
private boolean f2(int x, int y) {
218+
for (int i = 0; i < 3; ++i) {
219+
if (x % 3 == y % 3) {
220+
return false;
221+
}
222+
x /= 3;
223+
y /= 3;
224+
}
225+
return true;
226+
}
227+
}
228+
```
229+
112230
### **C++**
113231

114232
```cpp
@@ -130,6 +248,69 @@ public:
130248
};
131249
```
132250
251+
```cpp
252+
class Solution {
253+
public:
254+
int numOfWays(int n) {
255+
int m = 27;
256+
257+
auto f1 = [&](int x) {
258+
int last = -1;
259+
for (int i = 0; i < 3; ++i) {
260+
if (x % 3 == last) {
261+
return false;
262+
}
263+
last = x % 3;
264+
x /= 3;
265+
}
266+
return true;
267+
};
268+
auto f2 = [&](int x, int y) {
269+
for (int i = 0; i < 3; ++i) {
270+
if (x % 3 == y % 3) {
271+
return false;
272+
}
273+
x /= 3;
274+
y /= 3;
275+
}
276+
return true;
277+
};
278+
279+
const int mod = 1e9 + 7;
280+
unordered_set<int> valid;
281+
vector<int> f(m);
282+
for (int i = 0; i < m; ++i) {
283+
if (f1(i)) {
284+
valid.insert(i);
285+
f[i] = 1;
286+
}
287+
}
288+
unordered_map<int, vector<int>> d;
289+
for (int i : valid) {
290+
for (int j : valid) {
291+
if (f2(i, j)) {
292+
d[i].push_back(j);
293+
}
294+
}
295+
}
296+
for (int k = 1; k < n; ++k) {
297+
vector<int> g(m);
298+
for (int i : valid) {
299+
for (int j : d[i]) {
300+
g[j] = (g[j] + f[i]) % mod;
301+
}
302+
}
303+
f = move(g);
304+
}
305+
int ans = 0;
306+
for (int x : f) {
307+
ans = (ans + x) % mod;
308+
}
309+
return ans;
310+
}
311+
};
312+
```
313+
133314
### **Go**
134315

135316
```go
@@ -146,6 +327,140 @@ func numOfWays(n int) int {
146327
}
147328
```
148329

330+
```go
331+
func numOfWays(n int) (ans int) {
332+
f1 := func(x int) bool {
333+
last := -1
334+
for i := 0; i < 3; i++ {
335+
if x%3 == last {
336+
return false
337+
}
338+
last = x % 3
339+
x /= 3
340+
}
341+
return true
342+
}
343+
f2 := func(x, y int) bool {
344+
for i := 0; i < 3; i++ {
345+
if x%3 == y%3 {
346+
return false
347+
}
348+
x /= 3
349+
y /= 3
350+
}
351+
return true
352+
}
353+
m := 27
354+
valid := map[int]bool{}
355+
f := make([]int, m)
356+
for i := 0; i < m; i++ {
357+
if f1(i) {
358+
valid[i] = true
359+
f[i] = 1
360+
}
361+
}
362+
d := map[int][]int{}
363+
for i := range valid {
364+
for j := range valid {
365+
if f2(i, j) {
366+
d[i] = append(d[i], j)
367+
}
368+
}
369+
}
370+
const mod int = 1e9 + 7
371+
for k := 1; k < n; k++ {
372+
g := make([]int, m)
373+
for i := range valid {
374+
for _, j := range d[i] {
375+
g[i] = (g[i] + f[j]) % mod
376+
}
377+
}
378+
f = g
379+
}
380+
for _, x := range f {
381+
ans = (ans + x) % mod
382+
}
383+
return
384+
}
385+
```
386+
387+
### **TypeScript**
388+
389+
```ts
390+
function numOfWays(n: number): number {
391+
const mod: number = 10 ** 9 + 7;
392+
let f0: number = 6;
393+
let f1: number = 6;
394+
395+
for (let i = 1; i < n; i++) {
396+
const g0: number = (3 * f0 + 2 * f1) % mod;
397+
const g1: number = (2 * f0 + 2 * f1) % mod;
398+
f0 = g0;
399+
f1 = g1;
400+
}
401+
402+
return (f0 + f1) % mod;
403+
}
404+
```
405+
406+
```ts
407+
function numOfWays(n: number): number {
408+
const f1 = (x: number): boolean => {
409+
let last = -1;
410+
for (let i = 0; i < 3; ++i) {
411+
if (x % 3 === last) {
412+
return false;
413+
}
414+
last = x % 3;
415+
x = Math.floor(x / 3);
416+
}
417+
return true;
418+
};
419+
const f2 = (x: number, y: number): boolean => {
420+
for (let i = 0; i < 3; ++i) {
421+
if (x % 3 === y % 3) {
422+
return false;
423+
}
424+
x = Math.floor(x / 3);
425+
y = Math.floor(y / 3);
426+
}
427+
return true;
428+
};
429+
const m = 27;
430+
const valid = new Set<number>();
431+
const f: number[] = Array(m).fill(0);
432+
for (let i = 0; i < m; ++i) {
433+
if (f1(i)) {
434+
valid.add(i);
435+
f[i] = 1;
436+
}
437+
}
438+
const d: Map<number, number[]> = new Map();
439+
for (const i of valid) {
440+
for (const j of valid) {
441+
if (f2(i, j)) {
442+
d.set(i, (d.get(i) || []).concat(j));
443+
}
444+
}
445+
}
446+
const mod = 10 ** 9 + 7;
447+
for (let k = 1; k < n; ++k) {
448+
const g: number[] = Array(m).fill(0);
449+
for (const i of valid) {
450+
for (const j of d.get(i) || []) {
451+
g[i] = (g[i] + f[j]) % mod;
452+
}
453+
}
454+
f.splice(0, f.length, ...g);
455+
}
456+
let ans = 0;
457+
for (const x of f) {
458+
ans = (ans + x) % mod;
459+
}
460+
return ans;
461+
}
462+
```
463+
149464
### **...**
150465

151466
```

0 commit comments

Comments
 (0)