Skip to content

Commit bed93c3

Browse files
authored
feat: add solutions to lc problem: No.0838 (#4383)
No.0838.Push Dominoes
1 parent 562547b commit bed93c3

File tree

3 files changed

+144
-110
lines changed

3 files changed

+144
-110
lines changed

solution/0800-0899/0838.Push Dominoes/README.md

+58-39
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ tags:
2929
<p>给你一个字符串 <code>dominoes</code> 表示这一行多米诺骨牌的初始状态,其中:</p>
3030

3131
<ul>
32-
<li><code>dominoes[i] = 'L'</code>,表示第 <code>i</code> 张多米诺骨牌被推向左侧,</li>
33-
<li><code>dominoes[i] = 'R'</code>,表示第 <code>i</code> 张多米诺骨牌被推向右侧,</li>
34-
<li><code>dominoes[i] = '.'</code>,表示没有推动第 <code>i</code> 张多米诺骨牌。</li>
32+
<li><code>dominoes[i] = 'L'</code>,表示第 <code>i</code> 张多米诺骨牌被推向左侧,</li>
33+
<li><code>dominoes[i] = 'R'</code>,表示第 <code>i</code> 张多米诺骨牌被推向右侧,</li>
34+
<li><code>dominoes[i] = '.'</code>,表示没有推动第 <code>i</code> 张多米诺骨牌。</li>
3535
</ul>
3636

3737
<p>返回表示最终状态的字符串。</p>
@@ -57,9 +57,9 @@ tags:
5757
<p><strong>提示:</strong></p>
5858

5959
<ul>
60-
<li><code>n == dominoes.length</code></li>
61-
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
62-
<li><code>dominoes[i]</code> 为 <code>'L'</code>、<code>'R'</code> 或 <code>'.'</code></li>
60+
<li><code>n == dominoes.length</code></li>
61+
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
62+
<li><code>dominoes[i]</code> 为 <code>'L'</code>、<code>'R'</code> 或 <code>'.'</code></li>
6363
</ul>
6464

6565
<!-- description:end -->
@@ -68,7 +68,30 @@ tags:
6868

6969
<!-- solution:start -->
7070

71-
### 方法一
71+
### 方法一:多源 BFS
72+
73+
把所有初始受到推力的骨牌(`L` 或 `R`)视作 **源点**,它们会同时向外扩散各自的力。用队列按时间层级(0, 1, 2 …)进行 BFS:
74+
75+
我们定义 $\text{time[i]}$ 记录第 *i* 张骨牌第一次受力的时刻,`-1` 表示尚未受力,定义 $\text{force[i]}$ 是一个长度可变的列表,存放该骨牌在同一时刻收到的方向(`'L'``'R'`)。初始时把所有 `L/R` 的下标压入队列,并将它们的时间置 0。
76+
77+
当弹出下标 *i* 时,若 $\text{force[i]}$ 只有一个方向,骨牌就会倒向该方向 $f$。设下一张骨牌下标为
78+
79+
$$
80+
j =
81+
\begin{cases}
82+
i - 1, & f = L,\\
83+
i + 1, & f = R.
84+
\end{cases}
85+
$$
86+
87+
若 $0 \leq j < n$:
88+
89+
- 若 $\text{time[j]}=-1$,说明 *j* 从未受力,记录 $\text{time[j]}=\text{time[i]}+1$ 并入队,同时把 $f$ 写入 $\text{force[j]}$。
90+
- 若 $\text{time[j]}=\text{time[i]}+1$,说明它在同一“下一刻”已受过另一股力,此时只把 $f$ 追加到 $\text{force[j]}$,形成对冲;后续因 `len(force[j])==2`,它将保持竖直。
91+
92+
队列清空后,所有 $\text{force[i]}$ 长度为 1 的位置倒向对应方向;长度为 2 的位置保持 `.`。最终将字符数组拼接为答案。
93+
94+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是骨牌的数量。
7295

7396
<!-- tabs:start -->
7497

@@ -242,44 +265,40 @@ func pushDominoes(dominoes string) string {
242265
```ts
243266
function pushDominoes(dominoes: string): string {
244267
const n = dominoes.length;
245-
const map = {
246-
L: -1,
247-
R: 1,
248-
'.': 0,
249-
};
250-
let ans = new Array(n).fill(0);
251-
let visited = new Array(n).fill(0);
252-
let queue = [];
253-
let depth = 1;
268+
const q: number[] = [];
269+
const time: number[] = Array(n).fill(-1);
270+
const force: string[][] = Array.from({ length: n }, () => []);
271+
254272
for (let i = 0; i < n; i++) {
255-
let cur = map[dominoes.charAt(i)];
256-
if (cur) {
257-
queue.push(i);
258-
visited[i] = depth;
259-
ans[i] = cur;
273+
const f = dominoes[i];
274+
if (f !== '.') {
275+
q.push(i);
276+
time[i] = 0;
277+
force[i].push(f);
260278
}
261279
}
262-
while (queue.length) {
263-
depth++;
264-
let nextLevel = [];
265-
for (let i of queue) {
266-
const dx = ans[i];
267-
let x = i + dx;
268-
if (x >= 0 && x < n && [0, depth].includes(visited[x])) {
269-
ans[x] += dx;
270-
visited[x] = depth;
271-
nextLevel.push(x);
280+
281+
const ans: string[] = Array(n).fill('.');
282+
let head = 0;
283+
while (head < q.length) {
284+
const i = q[head++];
285+
if (force[i].length === 1) {
286+
const f = force[i][0];
287+
ans[i] = f;
288+
const j = f === 'L' ? i - 1 : i + 1;
289+
if (j >= 0 && j < n) {
290+
const t = time[i];
291+
if (time[j] === -1) {
292+
q.push(j);
293+
time[j] = t + 1;
294+
force[j].push(f);
295+
} else if (time[j] === t + 1) {
296+
force[j].push(f);
297+
}
272298
}
273299
}
274-
queue = nextLevel;
275300
}
276-
return ans
277-
.map(d => {
278-
if (!d) return '.';
279-
else if (d < 0) return 'L';
280-
else return 'R';
281-
})
282-
.join('');
301+
return ans.join('');
283302
}
284303
```
285304

solution/0800-0899/0838.Push Dominoes/README_EN.md

+58-39
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ tags:
2929
<p>You are given a string <code>dominoes</code> representing the initial state where:</p>
3030

3131
<ul>
32-
<li><code>dominoes[i] = &#39;L&#39;</code>, if the <code>i<sup>th</sup></code> domino has been pushed to the left,</li>
33-
<li><code>dominoes[i] = &#39;R&#39;</code>, if the <code>i<sup>th</sup></code> domino has been pushed to the right, and</li>
34-
<li><code>dominoes[i] = &#39;.&#39;</code>, if the <code>i<sup>th</sup></code> domino has not been pushed.</li>
32+
<li><code>dominoes[i] = &#39;L&#39;</code>, if the <code>i<sup>th</sup></code> domino has been pushed to the left,</li>
33+
<li><code>dominoes[i] = &#39;R&#39;</code>, if the <code>i<sup>th</sup></code> domino has been pushed to the right, and</li>
34+
<li><code>dominoes[i] = &#39;.&#39;</code>, if the <code>i<sup>th</sup></code> domino has not been pushed.</li>
3535
</ul>
3636

3737
<p>Return <em>a string representing the final state</em>.</p>
@@ -56,9 +56,9 @@ tags:
5656
<p><strong>Constraints:</strong></p>
5757

5858
<ul>
59-
<li><code>n == dominoes.length</code></li>
60-
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
61-
<li><code>dominoes[i]</code> is either <code>&#39;L&#39;</code>, <code>&#39;R&#39;</code>, or <code>&#39;.&#39;</code>.</li>
59+
<li><code>n == dominoes.length</code></li>
60+
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
61+
<li><code>dominoes[i]</code> is either <code>&#39;L&#39;</code>, <code>&#39;R&#39;</code>, or <code>&#39;.&#39;</code>.</li>
6262
</ul>
6363

6464
<!-- description:end -->
@@ -67,7 +67,30 @@ tags:
6767

6868
<!-- solution:start -->
6969

70-
### Solution 1
70+
### Solution 1: Multi-Source BFS
71+
72+
Treat all initially pushed dominoes (`L` or `R`) as **sources**, which simultaneously propagate their forces outward. Use a queue to perform BFS layer by layer (0, 1, 2, ...):
73+
74+
We define $\text{time[i]}$ to record the first moment when the _i_-th domino is affected by a force, with `-1` indicating it has not been affected yet. We also define $\text{force[i]}$ as a variable-length list that stores the directions (`'L'`, `'R'`) of forces acting on the domino at the same moment. Initially, push all indices of `L/R` dominoes into the queue and set their `time` to 0.
75+
76+
When dequeuing index _i_, if $\text{force[i]}$ contains only one direction, the domino will fall in that direction $f$. Let the index of the next domino be:
77+
78+
$$
79+
j =
80+
\begin{cases}
81+
i - 1, & f = L,\\
82+
i + 1, & f = R.
83+
\end{cases}
84+
$$
85+
86+
If $0 \leq j < n$:
87+
88+
- If $\text{time[j]} = -1$, it means _j_ has not been affected yet. Record $\text{time[j]} = \text{time[i]} + 1$, enqueue it, and append $f$ to $\text{force[j]}$.
89+
- If $\text{time[j]} = \text{time[i]} + 1$, it means _j_ has already been affected by another force at the same "next moment." In this case, append $f$ to $\text{force[j]}$, causing a standoff. Subsequently, since $\text{len(force[j])} = 2$, it will remain upright.
90+
91+
After the queue is emptied, all positions where $\text{force[i]}$ has a length of 1 will fall in the corresponding direction, while positions with a length of 2 will remain as `.`. Finally, concatenate the character array to form the answer.
92+
93+
The complexity is $O(n)$, and the space complexity is $O(n)$, where $n$ is the number of dominoes.
7194

7295
<!-- tabs:start -->
7396

@@ -241,44 +264,40 @@ func pushDominoes(dominoes string) string {
241264
```ts
242265
function pushDominoes(dominoes: string): string {
243266
const n = dominoes.length;
244-
const map = {
245-
L: -1,
246-
R: 1,
247-
'.': 0,
248-
};
249-
let ans = new Array(n).fill(0);
250-
let visited = new Array(n).fill(0);
251-
let queue = [];
252-
let depth = 1;
267+
const q: number[] = [];
268+
const time: number[] = Array(n).fill(-1);
269+
const force: string[][] = Array.from({ length: n }, () => []);
270+
253271
for (let i = 0; i < n; i++) {
254-
let cur = map[dominoes.charAt(i)];
255-
if (cur) {
256-
queue.push(i);
257-
visited[i] = depth;
258-
ans[i] = cur;
272+
const f = dominoes[i];
273+
if (f !== '.') {
274+
q.push(i);
275+
time[i] = 0;
276+
force[i].push(f);
259277
}
260278
}
261-
while (queue.length) {
262-
depth++;
263-
let nextLevel = [];
264-
for (let i of queue) {
265-
const dx = ans[i];
266-
let x = i + dx;
267-
if (x >= 0 && x < n && [0, depth].includes(visited[x])) {
268-
ans[x] += dx;
269-
visited[x] = depth;
270-
nextLevel.push(x);
279+
280+
const ans: string[] = Array(n).fill('.');
281+
let head = 0;
282+
while (head < q.length) {
283+
const i = q[head++];
284+
if (force[i].length === 1) {
285+
const f = force[i][0];
286+
ans[i] = f;
287+
const j = f === 'L' ? i - 1 : i + 1;
288+
if (j >= 0 && j < n) {
289+
const t = time[i];
290+
if (time[j] === -1) {
291+
q.push(j);
292+
time[j] = t + 1;
293+
force[j].push(f);
294+
} else if (time[j] === t + 1) {
295+
force[j].push(f);
296+
}
271297
}
272298
}
273-
queue = nextLevel;
274299
}
275-
return ans
276-
.map(d => {
277-
if (!d) return '.';
278-
else if (d < 0) return 'L';
279-
else return 'R';
280-
})
281-
.join('');
300+
return ans.join('');
282301
}
283302
```
284303

Original file line numberDiff line numberDiff line change
@@ -1,41 +1,37 @@
11
function pushDominoes(dominoes: string): string {
22
const n = dominoes.length;
3-
const map = {
4-
L: -1,
5-
R: 1,
6-
'.': 0,
7-
};
8-
let ans = new Array(n).fill(0);
9-
let visited = new Array(n).fill(0);
10-
let queue = [];
11-
let depth = 1;
3+
const q: number[] = [];
4+
const time: number[] = Array(n).fill(-1);
5+
const force: string[][] = Array.from({ length: n }, () => []);
6+
127
for (let i = 0; i < n; i++) {
13-
let cur = map[dominoes.charAt(i)];
14-
if (cur) {
15-
queue.push(i);
16-
visited[i] = depth;
17-
ans[i] = cur;
8+
const f = dominoes[i];
9+
if (f !== '.') {
10+
q.push(i);
11+
time[i] = 0;
12+
force[i].push(f);
1813
}
1914
}
20-
while (queue.length) {
21-
depth++;
22-
let nextLevel = [];
23-
for (let i of queue) {
24-
const dx = ans[i];
25-
let x = i + dx;
26-
if (x >= 0 && x < n && [0, depth].includes(visited[x])) {
27-
ans[x] += dx;
28-
visited[x] = depth;
29-
nextLevel.push(x);
15+
16+
const ans: string[] = Array(n).fill('.');
17+
let head = 0;
18+
while (head < q.length) {
19+
const i = q[head++];
20+
if (force[i].length === 1) {
21+
const f = force[i][0];
22+
ans[i] = f;
23+
const j = f === 'L' ? i - 1 : i + 1;
24+
if (j >= 0 && j < n) {
25+
const t = time[i];
26+
if (time[j] === -1) {
27+
q.push(j);
28+
time[j] = t + 1;
29+
force[j].push(f);
30+
} else if (time[j] === t + 1) {
31+
force[j].push(f);
32+
}
3033
}
3134
}
32-
queue = nextLevel;
3335
}
34-
return ans
35-
.map(d => {
36-
if (!d) return '.';
37-
else if (d < 0) return 'L';
38-
else return 'R';
39-
})
40-
.join('');
36+
return ans.join('');
4137
}

0 commit comments

Comments
 (0)