From 9e45ed253ab53a61b319596565630cd7e12ec71d Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 2 May 2025 22:01:29 +0800 Subject: [PATCH 1/2] feat: add solutions to lc problem: No.0838 No.0838.Push Dominoes --- .../0800-0899/0838.Push Dominoes/README.md | 95 +++++---- .../0800-0899/0838.Push Dominoes/README_EN.md | 185 ++++++++++-------- .../0800-0899/0838.Push Dominoes/Solution.ts | 60 +++--- 3 files changed, 196 insertions(+), 144 deletions(-) diff --git a/solution/0800-0899/0838.Push Dominoes/README.md b/solution/0800-0899/0838.Push Dominoes/README.md index e6f79c7abba0b..c8e1bce5c337d 100644 --- a/solution/0800-0899/0838.Push Dominoes/README.md +++ b/solution/0800-0899/0838.Push Dominoes/README.md @@ -68,7 +68,40 @@ tags: -### 方法一 +### 方法一:多源 BFS + +把所有初始受到推力的骨牌(`L` 或 `R`)视作 **源点**,它们会同时向外扩散各自的力。用队列按时间层级(0, 1, 2 …)进行 BFS: + +1. **建模** + + - `time[i]` 记录第 *i* 张骨牌第一次受力的时刻,`-1` 表示尚未受力。 + - `force[i]` 是一个长度可变的列表,存放该骨牌在同一时刻收到的方向(`'L'`、`'R'`)。 + - 初始时把所有 `L/R` 的下标压入队列,并将它们的时间置 0。 + +2. **扩散规则** + + - 当弹出下标 *i* 时,若 `force[i]` 只有一个方向,骨牌就会倒向该方向 `f`。 + - 设下一张骨牌下标为 + + $$ + j=\begin{cases} + i-1,& f=L\\[2pt] + i+1,& f=R + \end{cases} + $$ + + 若 `0 ≤ j < n`: + + - 若 `time[j]==-1`,说明 *j* 从未受力,记录 `time[j]=time[i]+1` 并入队,同时把 `f` 写入 `force[j]`。 + - 若 `time[j]==time[i]+1`,说明它在同一“下一刻”已受过另一股力,此时只把 `f` 追加到 `force[j]`,形成对冲;后续因 `len(force[j])==2`,它将保持竖直。 + +3. **终态判定** + + - 队列清空后,所有 `force[i]` 长度为 1 的位置倒向对应方向;长度为 2 的位置保持 `.`。最终将字符数组拼接为答案。 + +最终相似字符串组的数量就是并查集中连通分量的数量。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是骨牌的数量。 @@ -242,44 +275,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(''); } ``` diff --git a/solution/0800-0899/0838.Push Dominoes/README_EN.md b/solution/0800-0899/0838.Push Dominoes/README_EN.md index ce232677d18a7..dd0c204e4a3f4 100644 --- a/solution/0800-0899/0838.Push Dominoes/README_EN.md +++ b/solution/0800-0899/0838.Push Dominoes/README_EN.md @@ -29,9 +29,9 @@ tags:

You are given a string dominoes representing the initial state where:

Return a string representing the final state.

@@ -56,9 +56,9 @@ tags:

Constraints:

@@ -67,7 +67,38 @@ tags: -### Solution 1 +### Solution 1: Multi-Source BFS + +Treat all dominoes initially pushed (`L` or `R`) as **sources**, which simultaneously propagate their forces outward. Use a queue to perform BFS layer by layer (0, 1, 2, ...): + +1. **Modeling** + + - `time[i]` records the first moment when the _i_-th domino is affected by a force, with `-1` indicating it has not been affected yet. + - `force[i]` is 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. + +2. **Propagation Rules** + + - When dequeuing index _i_, if `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\\[2pt] + i+1,& f=R + \end{cases} + $$ + + If $0 \leq j < n$: + + - If `time[j] == -1`, it means _j_ has not been affected yet. Record `time[j] = time[i] + 1`, enqueue it, and append `f` to `force[j]`. + - If `time[j] == time[i] + 1`, it means _j_ has already been affected by another force at the same "next moment." In this case, append `f` to `force[j]`, causing a standoff. Subsequently, since `len(force[j]) == 2`, it will remain upright. + +3. **Final State Determination** + + - After the queue is emptied, all positions where `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. @@ -193,46 +224,46 @@ public: ```go func pushDominoes(dominoes string) string { - n := len(dominoes) - q := []int{} - time := make([]int, n) - for i := range time { - time[i] = -1 - } - force := make([][]byte, n) - for i, c := range dominoes { - if c != '.' { - q = append(q, i) - time[i] = 0 - force[i] = append(force[i], byte(c)) - } - } - - ans := bytes.Repeat([]byte{'.'}, n) - for len(q) > 0 { - i := q[0] - q = q[1:] - if len(force[i]) > 1 { - continue - } - f := force[i][0] - ans[i] = f - j := i - 1 - if f == 'R' { - j = i + 1 - } - if 0 <= j && j < n { - t := time[i] - if time[j] == -1 { - q = append(q, j) - time[j] = t + 1 - force[j] = append(force[j], f) - } else if time[j] == t+1 { - force[j] = append(force[j], f) - } - } - } - return string(ans) + n := len(dominoes) + q := []int{} + time := make([]int, n) + for i := range time { + time[i] = -1 + } + force := make([][]byte, n) + for i, c := range dominoes { + if c != '.' { + q = append(q, i) + time[i] = 0 + force[i] = append(force[i], byte(c)) + } + } + + ans := bytes.Repeat([]byte{'.'}, n) + for len(q) > 0 { + i := q[0] + q = q[1:] + if len(force[i]) > 1 { + continue + } + f := force[i][0] + ans[i] = f + j := i - 1 + if f == 'R' { + j = i + 1 + } + if 0 <= j && j < n { + t := time[i] + if time[j] == -1 { + q = append(q, j) + time[j] = t + 1 + force[j] = append(force[j], f) + } else if time[j] == t+1 { + force[j] = append(force[j], f) + } + } + } + return string(ans) } ``` @@ -241,44 +272,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(''); } ``` diff --git a/solution/0800-0899/0838.Push Dominoes/Solution.ts b/solution/0800-0899/0838.Push Dominoes/Solution.ts index d9e8412c5d062..0b912d31ca203 100644 --- a/solution/0800-0899/0838.Push Dominoes/Solution.ts +++ b/solution/0800-0899/0838.Push Dominoes/Solution.ts @@ -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(''); } From 710ed367f3b2926d1633fedbc4299862a56acfeb Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 2 May 2025 22:12:01 +0800 Subject: [PATCH 2/2] chore: update --- .../0800-0899/0838.Push Dominoes/README.md | 48 +++----- .../0800-0899/0838.Push Dominoes/README_EN.md | 116 ++++++++---------- 2 files changed, 73 insertions(+), 91 deletions(-) diff --git a/solution/0800-0899/0838.Push Dominoes/README.md b/solution/0800-0899/0838.Push Dominoes/README.md index c8e1bce5c337d..f9155dcaa5a0c 100644 --- a/solution/0800-0899/0838.Push Dominoes/README.md +++ b/solution/0800-0899/0838.Push Dominoes/README.md @@ -29,9 +29,9 @@ tags:

给你一个字符串 dominoes 表示这一行多米诺骨牌的初始状态,其中:

返回表示最终状态的字符串。

@@ -57,9 +57,9 @@ tags:

提示:

@@ -72,34 +72,24 @@ tags: 把所有初始受到推力的骨牌(`L` 或 `R`)视作 **源点**,它们会同时向外扩散各自的力。用队列按时间层级(0, 1, 2 …)进行 BFS: -1. **建模** +我们定义 $\text{time[i]}$ 记录第 *i* 张骨牌第一次受力的时刻,`-1` 表示尚未受力,定义 $\text{force[i]}$ 是一个长度可变的列表,存放该骨牌在同一时刻收到的方向(`'L'`、`'R'`)。初始时把所有 `L/R` 的下标压入队列,并将它们的时间置 0。 - - `time[i]` 记录第 *i* 张骨牌第一次受力的时刻,`-1` 表示尚未受力。 - - `force[i]` 是一个长度可变的列表,存放该骨牌在同一时刻收到的方向(`'L'`、`'R'`)。 - - 初始时把所有 `L/R` 的下标压入队列,并将它们的时间置 0。 +当弹出下标 *i* 时,若 $\text{force[i]}$ 只有一个方向,骨牌就会倒向该方向 $f$。设下一张骨牌下标为 -2. **扩散规则** +$$ +j = +\begin{cases} +i - 1, & f = L,\\ +i + 1, & f = R. +\end{cases} +$$ - - 当弹出下标 *i* 时,若 `force[i]` 只有一个方向,骨牌就会倒向该方向 `f`。 - - 设下一张骨牌下标为 +若 $0 \leq j < n$: - $$ - j=\begin{cases} - i-1,& f=L\\[2pt] - i+1,& f=R - \end{cases} - $$ +- 若 $\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`,它将保持竖直。 - 若 `0 ≤ j < n`: - - - 若 `time[j]==-1`,说明 *j* 从未受力,记录 `time[j]=time[i]+1` 并入队,同时把 `f` 写入 `force[j]`。 - - 若 `time[j]==time[i]+1`,说明它在同一“下一刻”已受过另一股力,此时只把 `f` 追加到 `force[j]`,形成对冲;后续因 `len(force[j])==2`,它将保持竖直。 - -3. **终态判定** - - - 队列清空后,所有 `force[i]` 长度为 1 的位置倒向对应方向;长度为 2 的位置保持 `.`。最终将字符数组拼接为答案。 - -最终相似字符串组的数量就是并查集中连通分量的数量。 +队列清空后,所有 $\text{force[i]}$ 长度为 1 的位置倒向对应方向;长度为 2 的位置保持 `.`。最终将字符数组拼接为答案。 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是骨牌的数量。 diff --git a/solution/0800-0899/0838.Push Dominoes/README_EN.md b/solution/0800-0899/0838.Push Dominoes/README_EN.md index dd0c204e4a3f4..d41fed93a68d5 100644 --- a/solution/0800-0899/0838.Push Dominoes/README_EN.md +++ b/solution/0800-0899/0838.Push Dominoes/README_EN.md @@ -69,34 +69,26 @@ tags: ### Solution 1: Multi-Source BFS -Treat all dominoes initially pushed (`L` or `R`) as **sources**, which simultaneously propagate their forces outward. Use a queue to perform BFS layer by layer (0, 1, 2, ...): +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, ...): -1. **Modeling** +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. - - `time[i]` records the first moment when the _i_-th domino is affected by a force, with `-1` indicating it has not been affected yet. - - `force[i]` is 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: -2. **Propagation Rules** +$$ +j = +\begin{cases} +i - 1, & f = L,\\ +i + 1, & f = R. +\end{cases} +$$ - - When dequeuing index _i_, if `force[i]` contains only one direction, the domino will fall in that direction `f`. - - Let the index of the next domino be: +If $0 \leq j < n$: - $$ - j=\begin{cases} - i-1,& f=L\\[2pt] - i+1,& f=R - \end{cases} - $$ +- 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. - If $0 \leq j < n$: - - - If `time[j] == -1`, it means _j_ has not been affected yet. Record `time[j] = time[i] + 1`, enqueue it, and append `f` to `force[j]`. - - If `time[j] == time[i] + 1`, it means _j_ has already been affected by another force at the same "next moment." In this case, append `f` to `force[j]`, causing a standoff. Subsequently, since `len(force[j]) == 2`, it will remain upright. - -3. **Final State Determination** - - - After the queue is emptied, all positions where `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. +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. @@ -224,46 +216,46 @@ public: ```go func pushDominoes(dominoes string) string { - n := len(dominoes) - q := []int{} - time := make([]int, n) - for i := range time { - time[i] = -1 - } - force := make([][]byte, n) - for i, c := range dominoes { - if c != '.' { - q = append(q, i) - time[i] = 0 - force[i] = append(force[i], byte(c)) - } - } - - ans := bytes.Repeat([]byte{'.'}, n) - for len(q) > 0 { - i := q[0] - q = q[1:] - if len(force[i]) > 1 { - continue - } - f := force[i][0] - ans[i] = f - j := i - 1 - if f == 'R' { - j = i + 1 - } - if 0 <= j && j < n { - t := time[i] - if time[j] == -1 { - q = append(q, j) - time[j] = t + 1 - force[j] = append(force[j], f) - } else if time[j] == t+1 { - force[j] = append(force[j], f) - } - } - } - return string(ans) + n := len(dominoes) + q := []int{} + time := make([]int, n) + for i := range time { + time[i] = -1 + } + force := make([][]byte, n) + for i, c := range dominoes { + if c != '.' { + q = append(q, i) + time[i] = 0 + force[i] = append(force[i], byte(c)) + } + } + + ans := bytes.Repeat([]byte{'.'}, n) + for len(q) > 0 { + i := q[0] + q = q[1:] + if len(force[i]) > 1 { + continue + } + f := force[i][0] + ans[i] = f + j := i - 1 + if f == 'R' { + j = i + 1 + } + if 0 <= j && j < n { + t := time[i] + if time[j] == -1 { + q = append(q, j) + time[j] = t + 1 + force[j] = append(force[j], f) + } else if time[j] == t+1 { + force[j] = append(force[j], f) + } + } + } + return string(ans) } ```