Skip to content

Commit 9f4cdb7

Browse files
authored
feat: add solutions to lc problem: No.2147 (doocs#3509)
No.2147.Number of Ways to Divide a Long Corridor
1 parent 4ef0040 commit 9f4cdb7

File tree

13 files changed

+578
-284
lines changed

13 files changed

+578
-284
lines changed

solution/2100-2199/2147.Number of Ways to Divide a Long Corridor/README.md

Lines changed: 206 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,21 @@ tags:
7878

7979
### 方法一:记忆化搜索
8080

81-
设计函数 `dfs(i, cnt)` 表示从下标 `i` 开始,且当前已经分配了 `cnt` 个座位的方案数
81+
我们设计一个函数 $\textit{dfs}(i, k)$,表示在走廊的第 $i$ 个位置,已经放置了 $k$ 个屏风的情况下,划分走廊的方案数。那么答案就是 $\textit{dfs}(0, 0)$
8282

83-
对于下标 `i` 处的字符,如果是 `S`,那么 `cnt``1`,如果此时 `cnt` 超过 `2`,那么直接返回 `0`
83+
函数 $\textit{dfs}(i, k)$ 的计算过程如下:
8484

85-
否则我们可以选择不放置屏风,此时的方案数为 `dfs(i + 1, cnt)`;如果此时 `cnt``2`,我们还可以选择放置屏风,此时的方案数为 `dfs(i + 1, 0)`
85+
如果 $i \geq \textit{len}(\textit{corridor})$,表示已经遍历完了走廊,此时如果 $k = 2$,说明找到了一种划分走廊的方案,返回 $1$,否则返回 $0$;
8686

87-
最终返回方案数,记忆化搜索即可。
87+
否则,我们需要考虑当前位置 $i$ 的情况:
8888

89-
时间复杂度 $O(n\times 3)$,空间复杂度 $O(n\times 3)$。其中 $n$ 为字符串 `corridor` 的长度。
89+
- 如果 $\textit{corridor}[i] = \text{'S'}$,表示当前位置是一个座位,我们将 $k$ 加 $1$;
90+
- 如果 $k > 2$,表示当前位置放置的屏风数量超过了 $2$,返回 $0$;
91+
- 否则,我们可以选择不放置屏风,即 $\textit{dfs}(i + 1, k)$;如果 $k = 2$,我们还可以选择放置屏风,即 $\textit{dfs}(i + 1, 0)$;我们将这两种情况的结果相加并取模 $10^9 + 7$,即 $\textit{ans} = (\textit{ans} + \textit{dfs}(i + 1, k)) \bmod \text{mod}$。
92+
93+
最后,我们返回 $\textit{dfs}(0, 0)$。
94+
95+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是走廊的长度。
9096

9197
<!-- tabs:start -->
9298

@@ -96,19 +102,17 @@ tags:
96102
class Solution:
97103
def numberOfWays(self, corridor: str) -> int:
98104
@cache
99-
def dfs(i, cnt):
100-
if i == n:
101-
return int(cnt == 2)
102-
cnt += corridor[i] == 'S'
103-
if cnt > 2:
105+
def dfs(i: int, k: int) -> int:
106+
if i >= len(corridor):
107+
return int(k == 2)
108+
k += int(corridor[i] == "S")
109+
if k > 2:
104110
return 0
105-
ans = dfs(i + 1, cnt)
106-
if cnt == 2:
107-
ans += dfs(i + 1, 0)
108-
ans %= mod
111+
ans = dfs(i + 1, k)
112+
if k == 2:
113+
ans = (ans + dfs(i + 1, 0)) % mod
109114
return ans
110115

111-
n = len(corridor)
112116
mod = 10**9 + 7
113117
ans = dfs(0, 0)
114118
dfs.cache_clear()
@@ -119,39 +123,34 @@ class Solution:
119123

120124
```java
121125
class Solution {
122-
private String s;
123126
private int n;
124-
private int[][] f;
125-
private static final int MOD = (int) 1e9 + 7;
127+
private char[] s;
128+
private Integer[][] f;
129+
private final int mod = (int) 1e9 + 7;
126130

127131
public int numberOfWays(String corridor) {
128-
s = corridor;
129-
n = s.length();
130-
f = new int[n][3];
131-
for (var e : f) {
132-
Arrays.fill(e, -1);
133-
}
132+
s = corridor.toCharArray();
133+
n = s.length;
134+
f = new Integer[n][3];
134135
return dfs(0, 0);
135136
}
136137

137-
private int dfs(int i, int cnt) {
138-
if (i == n) {
139-
return cnt == 2 ? 1 : 0;
138+
private int dfs(int i, int k) {
139+
if (i >= n) {
140+
return k == 2 ? 1 : 0;
140141
}
141-
cnt += s.charAt(i) == 'S' ? 1 : 0;
142-
if (cnt > 2) {
143-
return 0;
142+
if (f[i][k] != null) {
143+
return f[i][k];
144144
}
145-
if (f[i][cnt] != -1) {
146-
return f[i][cnt];
145+
k += s[i] == 'S' ? 1 : 0;
146+
if (k > 2) {
147+
return 0;
147148
}
148-
int ans = dfs(i + 1, cnt);
149-
if (cnt == 2) {
150-
ans += dfs(i + 1, 0);
151-
ans %= MOD;
149+
int ans = dfs(i + 1, k);
150+
if (k == 2) {
151+
ans = (ans + dfs(i + 1, 0)) % mod;
152152
}
153-
f[i][cnt] = ans;
154-
return ans;
153+
return f[i][k] = ans;
155154
}
156155
}
157156
```
@@ -161,26 +160,29 @@ class Solution {
161160
```cpp
162161
class Solution {
163162
public:
164-
const int mod = 1e9 + 7;
165-
166163
int numberOfWays(string corridor) {
167164
int n = corridor.size();
168-
vector<vector<int>> f(n, vector<int>(3, -1));
169-
function<int(int, int)> dfs;
170-
dfs = [&](int i, int cnt) {
171-
if (i == n) return cnt == 2 ? 1 : 0;
172-
cnt += corridor[i] == 'S';
173-
if (cnt > 2) return 0;
174-
if (f[i][cnt] != -1) return f[i][cnt];
175-
int ans = dfs(i + 1, cnt);
176-
if (cnt == 2) {
177-
ans += dfs(i + 1, 0);
178-
ans %= mod;
165+
int f[n][3];
166+
memset(f, -1, sizeof(f));
167+
const int mod = 1e9 + 7;
168+
auto dfs = [&](auto&& dfs, int i, int k) -> int {
169+
if (i >= n) {
170+
return k == 2;
179171
}
180-
f[i][cnt] = ans;
181-
return ans;
172+
if (f[i][k] != -1) {
173+
return f[i][k];
174+
}
175+
k += corridor[i] == 'S';
176+
if (k > 2) {
177+
return 0;
178+
}
179+
f[i][k] = dfs(dfs, i + 1, k);
180+
if (k == 2) {
181+
f[i][k] = (f[i][k] + dfs(dfs, i + 1, 0)) % mod;
182+
}
183+
return f[i][k];
182184
};
183-
return dfs(0, 0);
185+
return dfs(dfs, 0, 0);
184186
}
185187
};
186188
```
@@ -190,38 +192,33 @@ public:
190192
```go
191193
func numberOfWays(corridor string) int {
192194
n := len(corridor)
193-
var mod int = 1e9 + 7
194-
f := make([][]int, n)
195+
f := make([][3]int, n)
195196
for i := range f {
196-
f[i] = make([]int, 3)
197-
for j := range f[i] {
198-
f[i][j] = -1
199-
}
197+
f[i] = [3]int{-1, -1, -1}
200198
}
201-
var dfs func(i, cnt int) int
202-
dfs = func(i, cnt int) int {
203-
if i == n {
204-
if cnt == 2 {
199+
const mod = 1e9 + 7
200+
var dfs func(int, int) int
201+
dfs = func(i, k int) int {
202+
if i >= n {
203+
if k == 2 {
205204
return 1
206205
}
207206
return 0
208207
}
208+
if f[i][k] != -1 {
209+
return f[i][k]
210+
}
209211
if corridor[i] == 'S' {
210-
cnt++
212+
k++
211213
}
212-
if cnt > 2 {
214+
if k > 2 {
213215
return 0
214216
}
215-
if f[i][cnt] != -1 {
216-
return f[i][cnt]
217-
}
218-
ans := dfs(i+1, cnt)
219-
if cnt == 2 {
220-
ans += dfs(i+1, 0)
221-
ans %= mod
217+
f[i][k] = dfs(i+1, k)
218+
if k == 2 {
219+
f[i][k] = (f[i][k] + dfs(i+1, 0)) % mod
222220
}
223-
f[i][cnt] = ans
224-
return ans
221+
return f[i][k]
225222
}
226223
return dfs(0, 0)
227224
}
@@ -231,26 +228,148 @@ func numberOfWays(corridor string) int {
231228

232229
```ts
233230
function numberOfWays(corridor: string): number {
234-
const M: number = 1e9 + 7;
235-
const seatNumbers: number[] = [];
231+
const n = corridor.length;
232+
const mod = 10 ** 9 + 7;
233+
const f: number[][] = Array.from({ length: n }, () => Array(3).fill(-1));
234+
const dfs = (i: number, k: number): number => {
235+
if (i >= n) {
236+
return k === 2 ? 1 : 0;
237+
}
238+
if (f[i][k] !== -1) {
239+
return f[i][k];
240+
}
241+
if (corridor[i] === 'S') {
242+
++k;
243+
}
244+
if (k > 2) {
245+
return (f[i][k] = 0);
246+
}
247+
f[i][k] = dfs(i + 1, k);
248+
if (k === 2) {
249+
f[i][k] = (f[i][k] + dfs(i + 1, 0)) % mod;
250+
}
251+
return f[i][k];
252+
};
253+
return dfs(0, 0);
254+
}
255+
```
256+
257+
<!-- tabs:end -->
258+
259+
<!-- solution:end -->
260+
261+
<!-- solution:start -->
262+
263+
### 方法二:数学
264+
265+
我们可以将每两个座位划分为一组。在相邻的两组座位之间,如果前一组的最后一个座位和后一组的第一个座位之间的距离为 $x$,那么就有 $x$ 种放置屏风的方案。
266+
267+
我们遍历走廊,用一个变量 $\textit{cnt}$ 记录当前座位数,用一个变量 $\textit{last}$ 记录上一个座位的位置。
236268

237-
for (let i = 0; i < corridor.length; i++) {
238-
if (corridor.charAt(i) === 'S') {
239-
seatNumbers.push(i);
269+
当遍历到一个座位时,我们将 $\textit{cnt}$ 加 $1$,如果 $\textit{cnt}$ 大于 $2$ 且 $\textit{cnt}$ 为奇数,那么我们就需要在 $\textit{last}$ 和当前座位之间放置一个屏风,此时的方案数就是 $\textit{ans} \times (i - \textit{last})$,其中 $\textit{ans}$ 是之前的方案数。然后,我们更新 $\textit{last}$ 为当前座位的位置 $i$。
270+
271+
最后,如果 $\textit{cnt}$ 大于 $0$ 且 $\textit{cnt}$ 为偶数,那么返回 $\textit{ans}$,否则返回 $0$。
272+
273+
时间复杂度 $O(n)$,其中 $n$ 是走廊的长度。空间复杂度 $O(1)$。
274+
275+
<!-- tabs:start -->
276+
277+
#### Python3
278+
279+
```python
280+
class Solution:
281+
def numberOfWays(self, corridor: str) -> int:
282+
mod = 10**9 + 7
283+
ans, cnt, last = 1, 0, 0
284+
for i, c in enumerate(corridor):
285+
if c == "S":
286+
cnt += 1
287+
if cnt > 2 and cnt % 2:
288+
ans = ans * (i - last) % mod
289+
last = i
290+
return ans if cnt and cnt % 2 == 0 else 0
291+
```
292+
293+
#### Java
294+
295+
```java
296+
class Solution {
297+
public int numberOfWays(String corridor) {
298+
final int mod = (int) 1e9 + 7;
299+
long ans = 1, cnt = 0, last = 0;
300+
for (int i = 0; i < corridor.length(); ++i) {
301+
if (corridor.charAt(i) == 'S') {
302+
if (++cnt > 2 && cnt % 2 == 1) {
303+
ans = ans * (i - last) % mod;
304+
}
305+
last = i;
306+
}
240307
}
308+
return cnt > 0 && cnt % 2 == 0 ? (int) ans : 0;
241309
}
310+
}
311+
```
312+
313+
#### C++
242314

243-
if (seatNumbers.length % 2 !== 0 || seatNumbers.length === 0) {
244-
return 0;
315+
```cpp
316+
class Solution {
317+
public:
318+
int numberOfWays(string corridor) {
319+
const int mod = 1e9 + 7;
320+
long long ans = 1;
321+
int cnt = 0, last = 0;
322+
for (int i = 0; i < corridor.length(); ++i) {
323+
if (corridor[i] == 'S') {
324+
if (++cnt > 2 && cnt % 2) {
325+
ans = ans * (i - last) % mod;
326+
}
327+
last = i;
328+
}
329+
}
330+
return cnt > 0 && cnt % 2 == 0 ? ans : 0;
245331
}
332+
};
333+
```
246334
247-
let result: number = 1;
335+
#### Go
248336
249-
for (let i = 2; i < seatNumbers.length; i += 2) {
250-
result = (result * (seatNumbers[i] - seatNumbers[i - 1])) % M;
251-
}
337+
```go
338+
func numberOfWays(corridor string) int {
339+
const mod int = 1e9 + 7
340+
ans, cnt, last := 1, 0, 0
341+
for i, c := range corridor {
342+
if c == 'S' {
343+
cnt++
344+
if cnt > 2 && cnt%2 == 1 {
345+
ans = ans * (i - last) % mod
346+
}
347+
last = i
348+
}
349+
}
350+
if cnt > 0 && cnt%2 == 0 {
351+
return ans
352+
}
353+
return 0
354+
}
355+
```
356+
357+
#### TypeScript
252358

253-
return result;
359+
```ts
360+
function numberOfWays(corridor: string): number {
361+
const mod = 10 ** 9 + 7;
362+
const n = corridor.length;
363+
let [ans, cnt, last] = [1, 0, 0];
364+
for (let i = 0; i < n; ++i) {
365+
if (corridor[i] === 'S') {
366+
if (++cnt > 2 && cnt % 2) {
367+
ans = (ans * (i - last)) % mod;
368+
}
369+
last = i;
370+
}
371+
}
372+
return cnt > 0 && cnt % 2 === 0 ? ans : 0;
254373
}
255374
```
256375

0 commit comments

Comments
 (0)