Skip to content

feat: add solutions to lc problem: No.0838 #4383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 58 additions & 39 deletions solution/0800-0899/0838.Push Dominoes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ tags:
<p>给你一个字符串 <code>dominoes</code> 表示这一行多米诺骨牌的初始状态,其中:</p>

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

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

<ul>
<li><code>n == dominoes.length</code></li>
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
<li><code>dominoes[i]</code> 为 <code>'L'</code>、<code>'R'</code> 或 <code>'.'</code></li>
<li><code>n == dominoes.length</code></li>
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
<li><code>dominoes[i]</code> 为 <code>'L'</code>、<code>'R'</code> 或 <code>'.'</code></li>
</ul>

<!-- description:end -->
Expand All @@ -68,7 +68,30 @@ tags:

<!-- solution:start -->

### 方法一
### 方法一:多源 BFS

把所有初始受到推力的骨牌(`L` 或 `R`)视作 **源点**,它们会同时向外扩散各自的力。用队列按时间层级(0, 1, 2 …)进行 BFS:

我们定义 $\text{time[i]}$ 记录第 *i* 张骨牌第一次受力的时刻,`-1` 表示尚未受力,定义 $\text{force[i]}$ 是一个长度可变的列表,存放该骨牌在同一时刻收到的方向(`'L'`、`'R'`)。初始时把所有 `L/R` 的下标压入队列,并将它们的时间置 0。

当弹出下标 *i* 时,若 $\text{force[i]}$ 只有一个方向,骨牌就会倒向该方向 $f$。设下一张骨牌下标为

$$
j =
\begin{cases}
i - 1, & f = L,\\
i + 1, & f = R.
\end{cases}
$$

若 $0 \leq j < n$:

- 若 $\text{time[j]}=-1$,说明 *j* 从未受力,记录 $\text{time[j]}=\text{time[i]}+1$ 并入队,同时把 $f$ 写入 $\text{force[j]}$。
- 若 $\text{time[j]}=\text{time[i]}+1$,说明它在同一“下一刻”已受过另一股力,此时只把 $f$ 追加到 $\text{force[j]}$,形成对冲;后续因 `len(force[j])==2`,它将保持竖直。

队列清空后,所有 $\text{force[i]}$ 长度为 1 的位置倒向对应方向;长度为 2 的位置保持 `.`。最终将字符数组拼接为答案。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是骨牌的数量。

<!-- tabs:start -->

Expand Down Expand Up @@ -242,44 +265,40 @@ func pushDominoes(dominoes string) string {
```ts
function pushDominoes(dominoes: string): string {
const n = dominoes.length;
const map = {
L: -1,
R: 1,
'.': 0,
};
let ans = new Array(n).fill(0);
let visited = new Array(n).fill(0);
let queue = [];
let depth = 1;
const q: number[] = [];
const time: number[] = Array(n).fill(-1);
const force: string[][] = Array.from({ length: n }, () => []);

for (let i = 0; i < n; i++) {
let cur = map[dominoes.charAt(i)];
if (cur) {
queue.push(i);
visited[i] = depth;
ans[i] = cur;
const f = dominoes[i];
if (f !== '.') {
q.push(i);
time[i] = 0;
force[i].push(f);
}
}
while (queue.length) {
depth++;
let nextLevel = [];
for (let i of queue) {
const dx = ans[i];
let x = i + dx;
if (x >= 0 && x < n && [0, depth].includes(visited[x])) {
ans[x] += dx;
visited[x] = depth;
nextLevel.push(x);

const ans: string[] = Array(n).fill('.');
let head = 0;
while (head < q.length) {
const i = q[head++];
if (force[i].length === 1) {
const f = force[i][0];
ans[i] = f;
const j = f === 'L' ? i - 1 : i + 1;
if (j >= 0 && j < n) {
const t = time[i];
if (time[j] === -1) {
q.push(j);
time[j] = t + 1;
force[j].push(f);
} else if (time[j] === t + 1) {
force[j].push(f);
}
}
}
queue = nextLevel;
}
return ans
.map(d => {
if (!d) return '.';
else if (d < 0) return 'L';
else return 'R';
})
.join('');
return ans.join('');
}
```

Expand Down
97 changes: 58 additions & 39 deletions solution/0800-0899/0838.Push Dominoes/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ tags:
<p>You are given a string <code>dominoes</code> representing the initial state where:</p>

<ul>
<li><code>dominoes[i] = &#39;L&#39;</code>, if the <code>i<sup>th</sup></code> domino has been pushed to the left,</li>
<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>
<li><code>dominoes[i] = &#39;.&#39;</code>, if the <code>i<sup>th</sup></code> domino has not been pushed.</li>
<li><code>dominoes[i] = &#39;L&#39;</code>, if the <code>i<sup>th</sup></code> domino has been pushed to the left,</li>
<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>
<li><code>dominoes[i] = &#39;.&#39;</code>, if the <code>i<sup>th</sup></code> domino has not been pushed.</li>
</ul>

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

<ul>
<li><code>n == dominoes.length</code></li>
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
<li><code>dominoes[i]</code> is either <code>&#39;L&#39;</code>, <code>&#39;R&#39;</code>, or <code>&#39;.&#39;</code>.</li>
<li><code>n == dominoes.length</code></li>
<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
<li><code>dominoes[i]</code> is either <code>&#39;L&#39;</code>, <code>&#39;R&#39;</code>, or <code>&#39;.&#39;</code>.</li>
</ul>

<!-- description:end -->
Expand All @@ -67,7 +67,30 @@ tags:

<!-- solution:start -->

### Solution 1
### Solution 1: Multi-Source BFS

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, ...):

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.

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:

$$
j =
\begin{cases}
i - 1, & f = L,\\
i + 1, & f = R.
\end{cases}
$$

If $0 \leq j < n$:

- 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]}$.
- 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.

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.

The complexity is $O(n)$, and the space complexity is $O(n)$, where $n$ is the number of dominoes.

<!-- tabs:start -->

Expand Down Expand Up @@ -241,44 +264,40 @@ func pushDominoes(dominoes string) string {
```ts
function pushDominoes(dominoes: string): string {
const n = dominoes.length;
const map = {
L: -1,
R: 1,
'.': 0,
};
let ans = new Array(n).fill(0);
let visited = new Array(n).fill(0);
let queue = [];
let depth = 1;
const q: number[] = [];
const time: number[] = Array(n).fill(-1);
const force: string[][] = Array.from({ length: n }, () => []);

for (let i = 0; i < n; i++) {
let cur = map[dominoes.charAt(i)];
if (cur) {
queue.push(i);
visited[i] = depth;
ans[i] = cur;
const f = dominoes[i];
if (f !== '.') {
q.push(i);
time[i] = 0;
force[i].push(f);
}
}
while (queue.length) {
depth++;
let nextLevel = [];
for (let i of queue) {
const dx = ans[i];
let x = i + dx;
if (x >= 0 && x < n && [0, depth].includes(visited[x])) {
ans[x] += dx;
visited[x] = depth;
nextLevel.push(x);

const ans: string[] = Array(n).fill('.');
let head = 0;
while (head < q.length) {
const i = q[head++];
if (force[i].length === 1) {
const f = force[i][0];
ans[i] = f;
const j = f === 'L' ? i - 1 : i + 1;
if (j >= 0 && j < n) {
const t = time[i];
if (time[j] === -1) {
q.push(j);
time[j] = t + 1;
force[j].push(f);
} else if (time[j] === t + 1) {
force[j].push(f);
}
}
}
queue = nextLevel;
}
return ans
.map(d => {
if (!d) return '.';
else if (d < 0) return 'L';
else return 'R';
})
.join('');
return ans.join('');
}
```

Expand Down
60 changes: 28 additions & 32 deletions solution/0800-0899/0838.Push Dominoes/Solution.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
function pushDominoes(dominoes: string): string {
const n = dominoes.length;
const map = {
L: -1,
R: 1,
'.': 0,
};
let ans = new Array(n).fill(0);
let visited = new Array(n).fill(0);
let queue = [];
let depth = 1;
const q: number[] = [];
const time: number[] = Array(n).fill(-1);
const force: string[][] = Array.from({ length: n }, () => []);

for (let i = 0; i < n; i++) {
let cur = map[dominoes.charAt(i)];
if (cur) {
queue.push(i);
visited[i] = depth;
ans[i] = cur;
const f = dominoes[i];
if (f !== '.') {
q.push(i);
time[i] = 0;
force[i].push(f);
}
}
while (queue.length) {
depth++;
let nextLevel = [];
for (let i of queue) {
const dx = ans[i];
let x = i + dx;
if (x >= 0 && x < n && [0, depth].includes(visited[x])) {
ans[x] += dx;
visited[x] = depth;
nextLevel.push(x);

const ans: string[] = Array(n).fill('.');
let head = 0;
while (head < q.length) {
const i = q[head++];
if (force[i].length === 1) {
const f = force[i][0];
ans[i] = f;
const j = f === 'L' ? i - 1 : i + 1;
if (j >= 0 && j < n) {
const t = time[i];
if (time[j] === -1) {
q.push(j);
time[j] = t + 1;
force[j].push(f);
} else if (time[j] === t + 1) {
force[j].push(f);
}
}
}
queue = nextLevel;
}
return ans
.map(d => {
if (!d) return '.';
else if (d < 0) return 'L';
else return 'R';
})
.join('');
return ans.join('');
}