,
+ trie: Trie,
+}
+
+impl MapSum {
+ fn new() -> Self {
+ MapSum {
+ d: std::collections::HashMap::new(),
+ trie: Trie::new(),
+ }
+ }
+
+ fn insert(&mut self, key: String, val: i32) {
+ let x = val - self.d.get(&key).unwrap_or(&0);
+ self.d.insert(key.clone(), val);
+ self.trie.insert(&key, x);
+ }
+
+ fn sum(&self, prefix: String) -> i32 {
+ self.trie.search(&prefix)
+ }
+}
diff --git a/solution/0600-0699/0684.Redundant Connection/README.md b/solution/0600-0699/0684.Redundant Connection/README.md
index 211bf86a82ed4..8be4a8e5ae755 100644
--- a/solution/0600-0699/0684.Redundant Connection/README.md
+++ b/solution/0600-0699/0684.Redundant Connection/README.md
@@ -21,7 +21,7 @@ tags:
树可以看成是一个连通且 无环 的 无向 图。
-给定往一棵 n
个节点 (节点值 1~n
) 的树中添加一条边后的图。添加的边的两个顶点包含在 1
到 n
中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n
的二维数组 edges
,edges[i] = [ai, bi]
表示图中在 ai
和 bi
之间存在一条边。
+给定一个图,该图从一棵 n
个节点 (节点值 1~n
) 的树中添加一条边后获得。添加的边的两个不同顶点编号在 1
到 n
中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n
的二维数组 edges
,edges[i] = [ai, bi]
表示图中在 ai
和 bi
之间存在一条边。
请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n
个节点的树。如果有多个答案,则返回数组 edges
中最后出现的那个。
diff --git a/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README.md b/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README.md
index e38ac3f85c916..71916586e7a7e 100644
--- a/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README.md
+++ b/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README.md
@@ -5,6 +5,8 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/0600-0699/0689.Ma
tags:
- 数组
- 动态规划
+ - 前缀和
+ - 滑动窗口
---
@@ -29,7 +31,7 @@ tags:
输入:nums = [1,2,1,2,6,7,5,1], k = 2
输出:[0,3,5]
解释:子数组 [1, 2], [2, 6], [7, 5] 对应的起始下标为 [0, 3, 5]。
-也可以取 [2, 1], 但是结果 [1, 3, 5] 在字典序上更小。
+也可以取 [2, 1], 但是结果 [1, 3, 5] 在字典序上更大。
示例 2:
diff --git a/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README_EN.md b/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README_EN.md
index 4f842e5001bae..3d1fb0e0c7da3 100644
--- a/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README_EN.md
+++ b/solution/0600-0699/0689.Maximum Sum of 3 Non-Overlapping Subarrays/README_EN.md
@@ -5,6 +5,8 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/0600-0699/0689.Ma
tags:
- Array
- Dynamic Programming
+ - Prefix Sum
+ - Sliding Window
---
@@ -28,7 +30,7 @@ tags:
Input: nums = [1,2,1,2,6,7,5,1], k = 2
Output: [0,3,5]
Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
-We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically smaller.
+We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger.
Example 2:
diff --git a/solution/0700-0799/0704.Binary Search/README.md b/solution/0700-0799/0704.Binary Search/README.md
index 293c01438e03b..e58c3aed1d10e 100644
--- a/solution/0700-0799/0704.Binary Search/README.md
+++ b/solution/0700-0799/0704.Binary Search/README.md
@@ -17,19 +17,23 @@ tags:
-给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
+给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果 target
存在返回下标,否则返回 -1
。
-
+
你必须编写一个具有 O(log n)
时间复杂度的算法。
+
+
示例 1:
-输入: nums
= [-1,0,3,5,9,12], target
= 9
+
+输入: nums
= [-1,0,3,5,9,12], target
= 9
输出: 4
解释: 9 出现在 nums
中并且下标为 4
示例 2:
-输入: nums
= [-1,0,3,5,9,12], target
= 2
+
+输入: nums
= [-1,0,3,5,9,12], target
= 2
输出: -1
解释: 2 不存在 nums
中因此返回 -1
diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/README.md b/solution/0700-0799/0720.Longest Word in Dictionary/README.md
index bf15fcb915ab3..3a80e81888f9e 100644
--- a/solution/0700-0799/0720.Longest Word in Dictionary/README.md
+++ b/solution/0700-0799/0720.Longest Word in Dictionary/README.md
@@ -20,7 +20,7 @@ tags:
-给出一个字符串数组 words
组成的一本英语词典。返回 words
中最长的一个单词,该单词是由 words
词典中其他单词逐步添加一个字母组成。
+给出一个字符串数组 words
组成的一本英语词典。返回能够通过 words
中其它单词逐步添加一个字母来构造得到的 words
中最长的单词。
若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。
diff --git a/solution/0700-0799/0752.Open the Lock/Solution.py b/solution/0700-0799/0752.Open the Lock/Solution.py
index 650d7757d7db7..76e24b06bb1ce 100644
--- a/solution/0700-0799/0752.Open the Lock/Solution.py
+++ b/solution/0700-0799/0752.Open the Lock/Solution.py
@@ -17,7 +17,7 @@ def next(s):
s = set(deadends)
if '0000' in s:
return -1
- q = deque([('0000')])
+ q = deque(['0000'])
s.add('0000')
ans = 0
while q:
diff --git a/solution/0700-0799/0752.Open the Lock/Solution2.py b/solution/0700-0799/0752.Open the Lock/Solution2.py
index 6a623bcf80b3b..87d7e03b99365 100644
--- a/solution/0700-0799/0752.Open the Lock/Solution2.py
+++ b/solution/0700-0799/0752.Open the Lock/Solution2.py
@@ -27,7 +27,7 @@ def extend(m1, m2, q):
def bfs():
m1, m2 = {"0000": 0}, {target: 0}
- q1, q2 = deque([('0000')]), deque([(target)])
+ q1, q2 = deque(['0000']), deque([target])
while q1 and q2:
t = extend(m1, m2, q1) if len(q1) <= len(q2) else extend(m2, m1, q2)
if t != -1:
diff --git a/solution/0700-0799/0759.Employee Free Time/README.md b/solution/0700-0799/0759.Employee Free Time/README.md
index cf8212b6bb7f5..e422bbd125252 100644
--- a/solution/0700-0799/0759.Employee Free Time/README.md
+++ b/solution/0700-0799/0759.Employee Free Time/README.md
@@ -5,6 +5,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/0700-0799/0759.Em
tags:
- 数组
- 排序
+ - 扫描线
- 堆(优先队列)
---
diff --git a/solution/0700-0799/0759.Employee Free Time/README_EN.md b/solution/0700-0799/0759.Employee Free Time/README_EN.md
index 9543d4e2e9379..7c0a64ed0b949 100644
--- a/solution/0700-0799/0759.Employee Free Time/README_EN.md
+++ b/solution/0700-0799/0759.Employee Free Time/README_EN.md
@@ -5,6 +5,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/0700-0799/0759.Em
tags:
- Array
- Sorting
+ - Line Sweep
- Heap (Priority Queue)
---
diff --git a/solution/0700-0799/0773.Sliding Puzzle/Solution.py b/solution/0700-0799/0773.Sliding Puzzle/Solution.py
index 897f9d185a622..9fe4e105727a7 100644
--- a/solution/0700-0799/0773.Sliding Puzzle/Solution.py
+++ b/solution/0700-0799/0773.Sliding Puzzle/Solution.py
@@ -29,7 +29,7 @@ def f():
if start == end:
return 0
vis = {start}
- q = deque([(start)])
+ q = deque([start])
ans = 0
while q:
ans += 1
diff --git a/solution/0700-0799/0781.Rabbits in Forest/README.md b/solution/0700-0799/0781.Rabbits in Forest/README.md
index a3cdab7dc9fe3..e0deffabd8ff3 100644
--- a/solution/0700-0799/0781.Rabbits in Forest/README.md
+++ b/solution/0700-0799/0781.Rabbits in Forest/README.md
@@ -159,4 +159,52 @@ function numRabbits(answers: number[]): number {
+### Solution 2: Greedy + Hash Map
+
+
+
+#### TypeScript
+
+```ts
+function numRabbits(answers: number[]): number {
+ const cnt: Record = {};
+ let ans = 0;
+
+ for (const x of answers) {
+ if (cnt[x]) {
+ cnt[x]--;
+ } else {
+ cnt[x] = x;
+ ans += x + 1;
+ }
+ }
+
+ return ans;
+}
+```
+
+#### JavaScript
+
+```js
+function numRabbits(answers) {
+ const cnt = {};
+ let ans = 0;
+
+ for (const x of answers) {
+ if (cnt[x]) {
+ cnt[x]--;
+ } else {
+ cnt[x] = x;
+ ans += x + 1;
+ }
+ }
+
+ return ans;
+}
+```
+
+
+
+
+
diff --git a/solution/0700-0799/0781.Rabbits in Forest/README_EN.md b/solution/0700-0799/0781.Rabbits in Forest/README_EN.md
index 64c4163676514..b59b36d70b1a3 100644
--- a/solution/0700-0799/0781.Rabbits in Forest/README_EN.md
+++ b/solution/0700-0799/0781.Rabbits in Forest/README_EN.md
@@ -157,4 +157,54 @@ function numRabbits(answers: number[]): number {
+
+
+### Solution 2: Greedy + Hash Map
+
+
+
+#### TypeScript
+
+```ts
+function numRabbits(answers: number[]): number {
+ const cnt: Record = {};
+ let ans = 0;
+
+ for (const x of answers) {
+ if (cnt[x]) {
+ cnt[x]--;
+ } else {
+ cnt[x] = x;
+ ans += x + 1;
+ }
+ }
+
+ return ans;
+}
+```
+
+#### JavaScript
+
+```js
+function numRabbits(answers) {
+ const cnt = {};
+ let ans = 0;
+
+ for (const x of answers) {
+ if (cnt[x]) {
+ cnt[x]--;
+ } else {
+ cnt[x] = x;
+ ans += x + 1;
+ }
+ }
+
+ return ans;
+}
+```
+
+
+
+
+
diff --git a/solution/0700-0799/0781.Rabbits in Forest/Solution2.js b/solution/0700-0799/0781.Rabbits in Forest/Solution2.js
new file mode 100644
index 0000000000000..24214b0b9c71a
--- /dev/null
+++ b/solution/0700-0799/0781.Rabbits in Forest/Solution2.js
@@ -0,0 +1,15 @@
+function numRabbits(answers) {
+ const cnt = {};
+ let ans = 0;
+
+ for (const x of answers) {
+ if (cnt[x]) {
+ cnt[x]--;
+ } else {
+ cnt[x] = x;
+ ans += x + 1;
+ }
+ }
+
+ return ans;
+}
diff --git a/solution/0700-0799/0781.Rabbits in Forest/Solution2.ts b/solution/0700-0799/0781.Rabbits in Forest/Solution2.ts
new file mode 100644
index 0000000000000..a87ad1d96eecd
--- /dev/null
+++ b/solution/0700-0799/0781.Rabbits in Forest/Solution2.ts
@@ -0,0 +1,15 @@
+function numRabbits(answers: number[]): number {
+ const cnt: Record = {};
+ let ans = 0;
+
+ for (const x of answers) {
+ if (cnt[x]) {
+ cnt[x]--;
+ } else {
+ cnt[x] = x;
+ ans += x + 1;
+ }
+ }
+
+ return ans;
+}
diff --git a/solution/0700-0799/0790.Domino and Tromino Tiling/README.md b/solution/0700-0799/0790.Domino and Tromino Tiling/README.md
index da30ee9b60a10..9311772e724de 100644
--- a/solution/0700-0799/0790.Domino and Tromino Tiling/README.md
+++ b/solution/0700-0799/0790.Domino and Tromino Tiling/README.md
@@ -86,7 +86,7 @@ tags:
注意,过程中的状态数值可能会很大,因此需要对 $10^9+7$ 取模。
-时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为面板的列数。
+时间复杂度 $O(n)$,其中 $n$ 为面板的列数。空间复杂度 $O(1)$。
@@ -132,12 +132,11 @@ class Solution {
```cpp
class Solution {
public:
- const int mod = 1e9 + 7;
-
int numTilings(int n) {
- long f[4] = {1, 0, 0, 0};
+ const int mod = 1e9 + 7;
+ long long f[4] = {1, 0, 0, 0};
for (int i = 1; i <= n; ++i) {
- long g[4] = {0, 0, 0, 0};
+ long long g[4];
g[0] = (f[0] + f[1] + f[2] + f[3]) % mod;
g[1] = (f[2] + f[3]) % mod;
g[2] = (f[1] + f[3]) % mod;
@@ -168,6 +167,46 @@ func numTilings(n int) int {
}
```
+#### TypeScript
+
+```ts
+function numTilings(n: number): number {
+ const mod = 1_000_000_007;
+ let f: number[] = [1, 0, 0, 0];
+
+ for (let i = 1; i <= n; ++i) {
+ const g: number[] = Array(4);
+ g[0] = (f[0] + f[1] + f[2] + f[3]) % mod;
+ g[1] = (f[2] + f[3]) % mod;
+ g[2] = (f[1] + f[3]) % mod;
+ g[3] = f[0] % mod;
+ f = g;
+ }
+
+ return f[0];
+}
+```
+
+#### Rust
+
+```rust
+impl Solution {
+ pub fn num_tilings(n: i32) -> i32 {
+ const MOD: i64 = 1_000_000_007;
+ let mut f: [i64; 4] = [1, 0, 0, 0];
+ for _ in 1..=n {
+ let mut g = [0i64; 4];
+ g[0] = (f[0] + f[1] + f[2] + f[3]) % MOD;
+ g[1] = (f[2] + f[3]) % MOD;
+ g[2] = (f[1] + f[3]) % MOD;
+ g[3] = f[0] % MOD;
+ f = g;
+ }
+ f[0] as i32
+ }
+}
+```
+
diff --git a/solution/0700-0799/0790.Domino and Tromino Tiling/README_EN.md b/solution/0700-0799/0790.Domino and Tromino Tiling/README_EN.md
index 04f89b3e86cd6..9d5dc63b7ff65 100644
--- a/solution/0700-0799/0790.Domino and Tromino Tiling/README_EN.md
+++ b/solution/0700-0799/0790.Domino and Tromino Tiling/README_EN.md
@@ -28,7 +28,7 @@ tags:
Input: n = 3
Output: 5
-Explanation: The five different ways are show above.
+Explanation: The five different ways are shown above.
Example 2:
@@ -126,12 +126,11 @@ class Solution {
```cpp
class Solution {
public:
- const int mod = 1e9 + 7;
-
int numTilings(int n) {
- long f[4] = {1, 0, 0, 0};
+ const int mod = 1e9 + 7;
+ long long f[4] = {1, 0, 0, 0};
for (int i = 1; i <= n; ++i) {
- long g[4] = {0, 0, 0, 0};
+ long long g[4];
g[0] = (f[0] + f[1] + f[2] + f[3]) % mod;
g[1] = (f[2] + f[3]) % mod;
g[2] = (f[1] + f[3]) % mod;
@@ -162,6 +161,46 @@ func numTilings(n int) int {
}
```
+#### TypeScript
+
+```ts
+function numTilings(n: number): number {
+ const mod = 1_000_000_007;
+ let f: number[] = [1, 0, 0, 0];
+
+ for (let i = 1; i <= n; ++i) {
+ const g: number[] = Array(4);
+ g[0] = (f[0] + f[1] + f[2] + f[3]) % mod;
+ g[1] = (f[2] + f[3]) % mod;
+ g[2] = (f[1] + f[3]) % mod;
+ g[3] = f[0] % mod;
+ f = g;
+ }
+
+ return f[0];
+}
+```
+
+#### Rust
+
+```rust
+impl Solution {
+ pub fn num_tilings(n: i32) -> i32 {
+ const MOD: i64 = 1_000_000_007;
+ let mut f: [i64; 4] = [1, 0, 0, 0];
+ for _ in 1..=n {
+ let mut g = [0i64; 4];
+ g[0] = (f[0] + f[1] + f[2] + f[3]) % MOD;
+ g[1] = (f[2] + f[3]) % MOD;
+ g[2] = (f[1] + f[3]) % MOD;
+ g[3] = f[0] % MOD;
+ f = g;
+ }
+ f[0] as i32
+ }
+}
+```
+
diff --git a/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.cpp b/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.cpp
index 7dee343d57916..835d82ee5f184 100644
--- a/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.cpp
+++ b/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.cpp
@@ -1,11 +1,10 @@
class Solution {
public:
- const int mod = 1e9 + 7;
-
int numTilings(int n) {
- long f[4] = {1, 0, 0, 0};
+ const int mod = 1e9 + 7;
+ long long f[4] = {1, 0, 0, 0};
for (int i = 1; i <= n; ++i) {
- long g[4] = {0, 0, 0, 0};
+ long long g[4];
g[0] = (f[0] + f[1] + f[2] + f[3]) % mod;
g[1] = (f[2] + f[3]) % mod;
g[2] = (f[1] + f[3]) % mod;
diff --git a/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.rs b/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.rs
new file mode 100644
index 0000000000000..fa193c65eb056
--- /dev/null
+++ b/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.rs
@@ -0,0 +1,15 @@
+impl Solution {
+ pub fn num_tilings(n: i32) -> i32 {
+ const MOD: i64 = 1_000_000_007;
+ let mut f: [i64; 4] = [1, 0, 0, 0];
+ for _ in 1..=n {
+ let mut g = [0i64; 4];
+ g[0] = (f[0] + f[1] + f[2] + f[3]) % MOD;
+ g[1] = (f[2] + f[3]) % MOD;
+ g[2] = (f[1] + f[3]) % MOD;
+ g[3] = f[0] % MOD;
+ f = g;
+ }
+ f[0] as i32
+ }
+}
diff --git a/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.ts b/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.ts
new file mode 100644
index 0000000000000..1550567f5375c
--- /dev/null
+++ b/solution/0700-0799/0790.Domino and Tromino Tiling/Solution.ts
@@ -0,0 +1,15 @@
+function numTilings(n: number): number {
+ const mod = 1_000_000_007;
+ let f: number[] = [1, 0, 0, 0];
+
+ for (let i = 1; i <= n; ++i) {
+ const g: number[] = Array(4);
+ g[0] = (f[0] + f[1] + f[2] + f[3]) % mod;
+ g[1] = (f[2] + f[3]) % mod;
+ g[2] = (f[1] + f[3]) % mod;
+ g[3] = f[0] % mod;
+ f = g;
+ }
+
+ return f[0];
+}
diff --git a/solution/0700-0799/0797.All Paths From Source to Target/README.md b/solution/0700-0799/0797.All Paths From Source to Target/README.md
index 4deb1aa603807..1d36139c345de 100644
--- a/solution/0700-0799/0797.All Paths From Source to Target/README.md
+++ b/solution/0700-0799/0797.All Paths From Source to Target/README.md
@@ -19,7 +19,7 @@ tags:
-给你一个有 n
个节点的 有向无环图(DAG),请你找出所有从节点 0
到节点 n-1
的路径并输出(不要求按特定顺序)
+给你一个有 n
个节点的 有向无环图(DAG),请你找出从节点 0
到节点 n-1
的所有路径并输出(不要求按特定顺序)
graph[i]
是一个从节点 i
可以访问的所有节点的列表(即从节点 i
到节点 graph[i][j]
存在一条有向边)。
diff --git a/solution/0800-0899/0802.Find Eventual Safe States/README.md b/solution/0800-0899/0802.Find Eventual Safe States/README.md
index efac1c82f3f3f..06994079ec0b8 100644
--- a/solution/0800-0899/0802.Find Eventual Safe States/README.md
+++ b/solution/0800-0899/0802.Find Eventual Safe States/README.md
@@ -21,7 +21,7 @@ tags:
有一个有 n
个节点的有向图,节点按 0
到 n - 1
编号。图由一个 索引从 0 开始 的 2D 整数数组 graph
表示, graph[i]
是与节点 i
相邻的节点的整数数组,这意味着从节点 i
到 graph[i]
中的每个节点都有一条边。
-如果一个节点没有连出的有向边,则该节点是 终端节点 。如果从该节点开始的所有可能路径都通向 终端节点 ,则该节点为 安全节点 。
+如果一个节点没有连出的有向边,则该节点是 终端节点 。如果从该节点开始的所有可能路径都通向 终端节点 ,则该节点为 终端节点(或另一个安全节点)。
返回一个由图中所有 安全节点 组成的数组作为答案。答案数组中的元素应当按 升序 排列。
diff --git a/solution/0800-0899/0819.Most Common Word/README.md b/solution/0800-0899/0819.Most Common Word/README.md
index f3adddcb4620e..20a453ae26ab5 100644
--- a/solution/0800-0899/0819.Most Common Word/README.md
+++ b/solution/0800-0899/0819.Most Common Word/README.md
@@ -23,6 +23,8 @@ tags:
paragraph
中的单词 不区分大小写 ,答案应以 小写 形式返回。
+注意 单词不包含标点符号。
+
示例 1:
diff --git a/solution/0800-0899/0819.Most Common Word/README_EN.md b/solution/0800-0899/0819.Most Common Word/README_EN.md
index ebcacda3c5c8e..2aae27ab03f78 100644
--- a/solution/0800-0899/0819.Most Common Word/README_EN.md
+++ b/solution/0800-0899/0819.Most Common Word/README_EN.md
@@ -23,6 +23,8 @@ tags:
The words in paragraph
are case-insensitive and the answer should be returned in lowercase.
+Note that words can not contain punctuation symbols.
+
Example 1:
diff --git a/solution/0800-0899/0822.Card Flipping Game/README.md b/solution/0800-0899/0822.Card Flipping Game/README.md
index 916b116f05012..460459ddaa715 100644
--- a/solution/0800-0899/0822.Card Flipping Game/README.md
+++ b/solution/0800-0899/0822.Card Flipping Game/README.md
@@ -66,7 +66,7 @@ tags:
### 方法一:哈希表
-我们注意到,对于位置 $i$,若 $fronts[i]$ 与 $backs[i]$ 元素相同,则一定不满足条件。
+我们注意到,对于位置 $i$,若 $\textit{fronts}[i]$ 与 $\textit{backs}[i]$ 元素相同,则一定不满足条件。
因此,我们先找出正面与背面相同的元素,记录在哈希表 $s$ 中。
@@ -195,6 +195,43 @@ function flipgame(fronts: number[], backs: number[]): number {
}
```
+#### Rust
+
+```rust
+use std::collections::HashSet;
+
+impl Solution {
+ pub fn flipgame(fronts: Vec, backs: Vec) -> i32 {
+ let n = fronts.len();
+ let mut s: HashSet = HashSet::new();
+
+ for i in 0..n {
+ if fronts[i] == backs[i] {
+ s.insert(fronts[i]);
+ }
+ }
+
+ let mut ans = 9999;
+ for &v in fronts.iter() {
+ if !s.contains(&v) {
+ ans = ans.min(v);
+ }
+ }
+ for &v in backs.iter() {
+ if !s.contains(&v) {
+ ans = ans.min(v);
+ }
+ }
+
+ if ans == 9999 {
+ 0
+ } else {
+ ans
+ }
+ }
+}
+```
+
#### C#
```cs
diff --git a/solution/0800-0899/0822.Card Flipping Game/README_EN.md b/solution/0800-0899/0822.Card Flipping Game/README_EN.md
index 89abfd94a2f80..dca0480e715a6 100644
--- a/solution/0800-0899/0822.Card Flipping Game/README_EN.md
+++ b/solution/0800-0899/0822.Card Flipping Game/README_EN.md
@@ -59,7 +59,17 @@ There are no good integers no matter how we flip the cards, so we return 0.
-### Solution 1
+### Solution 1: Hash Table
+
+We observe that for position $i$, if $\textit{fronts}[i]$ is equal to $\textit{backs}[i]$, then it certainly does not satisfy the condition.
+
+Therefore, we first identify all elements that appear the same on both the front and back sides and record them in a hash set $s$.
+
+Next, we iterate through all elements in both the front and back arrays. For any element $x$ that is **not** in the hash set $s$, we update the minimum value of the answer.
+
+Finally, if we find any element that satisfies the condition, we return the minimum answer; otherwise, we return $0$.
+
+The time complexity is $O(n)$ and the space complexity is $O(n)$, where $n$ is the length of the arrays.
@@ -180,6 +190,43 @@ function flipgame(fronts: number[], backs: number[]): number {
}
```
+#### Rust
+
+```rust
+use std::collections::HashSet;
+
+impl Solution {
+ pub fn flipgame(fronts: Vec, backs: Vec) -> i32 {
+ let n = fronts.len();
+ let mut s: HashSet = HashSet::new();
+
+ for i in 0..n {
+ if fronts[i] == backs[i] {
+ s.insert(fronts[i]);
+ }
+ }
+
+ let mut ans = 9999;
+ for &v in fronts.iter() {
+ if !s.contains(&v) {
+ ans = ans.min(v);
+ }
+ }
+ for &v in backs.iter() {
+ if !s.contains(&v) {
+ ans = ans.min(v);
+ }
+ }
+
+ if ans == 9999 {
+ 0
+ } else {
+ ans
+ }
+ }
+}
+```
+
#### C#
```cs
diff --git a/solution/0800-0899/0822.Card Flipping Game/Solution.rs b/solution/0800-0899/0822.Card Flipping Game/Solution.rs
new file mode 100644
index 0000000000000..25f15912f0308
--- /dev/null
+++ b/solution/0800-0899/0822.Card Flipping Game/Solution.rs
@@ -0,0 +1,32 @@
+use std::collections::HashSet;
+
+impl Solution {
+ pub fn flipgame(fronts: Vec, backs: Vec) -> i32 {
+ let n = fronts.len();
+ let mut s: HashSet = HashSet::new();
+
+ for i in 0..n {
+ if fronts[i] == backs[i] {
+ s.insert(fronts[i]);
+ }
+ }
+
+ let mut ans = 9999;
+ for &v in fronts.iter() {
+ if !s.contains(&v) {
+ ans = ans.min(v);
+ }
+ }
+ for &v in backs.iter() {
+ if !s.contains(&v) {
+ ans = ans.min(v);
+ }
+ }
+
+ if ans == 9999 {
+ 0
+ } else {
+ ans
+ }
+ }
+}
diff --git a/solution/0800-0899/0838.Push Dominoes/README.md b/solution/0800-0899/0838.Push Dominoes/README.md
index e6f79c7abba0b..d37d4feea673e 100644
--- a/solution/0800-0899/0838.Push Dominoes/README.md
+++ b/solution/0800-0899/0838.Push Dominoes/README.md
@@ -68,7 +68,30 @@ tags:
-### 方法一
+### 方法一:多源 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$ 是骨牌的数量。
@@ -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('');
}
```
diff --git a/solution/0800-0899/0838.Push Dominoes/README_EN.md b/solution/0800-0899/0838.Push Dominoes/README_EN.md
index ce232677d18a7..ec5ef4c80d36c 100644
--- a/solution/0800-0899/0838.Push Dominoes/README_EN.md
+++ b/solution/0800-0899/0838.Push Dominoes/README_EN.md
@@ -67,7 +67,30 @@ tags:
-### 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.
@@ -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('');
}
```
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('');
}
diff --git a/solution/0800-0899/0846.Hand of Straights/README.md b/solution/0800-0899/0846.Hand of Straights/README.md
index 42532a8a87d77..e3f2a87a9d75a 100644
--- a/solution/0800-0899/0846.Hand of Straights/README.md
+++ b/solution/0800-0899/0846.Hand of Straights/README.md
@@ -64,11 +64,15 @@ tags:
### 方法一:哈希表 + 排序
-我们先用哈希表 `cnt` 统计数组 `hand` 中每个数字出现的次数,然后对数组 `hand` 进行排序。
+我们首先判断数组 $\textit{hand}$ 的长度是否能被 $\textit{groupSize}$ 整除,如果不能整除,说明无法将数组划分成若干个长度为 $\textit{groupSize}$ 的子数组,直接返回 $\text{false}$。
-接下来,我们遍历数组 `hand`,对于数组中的每个数字 $v$,如果 $v$ 在哈希表 `cnt` 中出现的次数不为 $0$,则我们枚举 $v$ 到 $v+groupSize-1$ 的每个数字,如果这些数字在哈希表 `cnt` 中出现的次数都不为 $0$,则我们将这些数字的出现次数减 $1$,如果减 $1$ 后这些数字的出现次数为 $0$,则我们在哈希表 `cnt` 中删除这些数字。否则说明无法将数组划分成若干个长度为 $groupSize$ 的子数组,返回 `false`。如果可以将数组划分成若干个长度为 $groupSize$ 的子数组,则遍历结束后返回 `true`。
+接下来,我们用一个哈希表 $\textit{cnt}$ 统计数组 $\textit{hand}$ 中每个数字出现的次数,然后对数组 $\textit{hand}$ 进行排序。
-时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 `hand` 的长度。
+然后,我们遍历排序后的数组 $\textit{hand}$,对于每个数字 $x$,如果 $\textit{cnt}[x]$ 不为 $0$,我们枚举 $x$ 到 $x+\textit{groupSize}-1$ 的每个数字 $y$,如果 $\textit{cnt}[y]$ 为 $0$,说明无法将数组划分成若干个长度为 $\textit{groupSize}$ 的子数组,直接返回 $\text{false}$。否则,我们将 $\textit{cnt}[y]$ 减 $1$。
+
+遍历结束后,说明可以将数组划分成若干个长度为 $\textit{groupSize}$ 的子数组,返回 $\text{true}$。
+
+时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $\textit{hand}$ 的长度。
@@ -77,15 +81,15 @@ tags:
```python
class Solution:
def isNStraightHand(self, hand: List[int], groupSize: int) -> bool:
+ if len(hand) % groupSize:
+ return False
cnt = Counter(hand)
- for v in sorted(hand):
- if cnt[v]:
- for x in range(v, v + groupSize):
- if cnt[x] == 0:
+ for x in sorted(hand):
+ if cnt[x]:
+ for y in range(x, x + groupSize):
+ if cnt[y] == 0:
return False
- cnt[x] -= 1
- if cnt[x] == 0:
- cnt.pop(x)
+ cnt[y] -= 1
return True
```
@@ -94,21 +98,20 @@ class Solution:
```java
class Solution {
public boolean isNStraightHand(int[] hand, int groupSize) {
- Map cnt = new HashMap<>();
- for (int v : hand) {
- cnt.put(v, cnt.getOrDefault(v, 0) + 1);
+ if (hand.length % groupSize != 0) {
+ return false;
}
Arrays.sort(hand);
- for (int v : hand) {
- if (cnt.containsKey(v)) {
- for (int x = v; x < v + groupSize; ++x) {
- if (!cnt.containsKey(x)) {
+ Map cnt = new HashMap<>();
+ for (int x : hand) {
+ cnt.merge(x, 1, Integer::sum);
+ }
+ for (int x : hand) {
+ if (cnt.getOrDefault(x, 0) > 0) {
+ for (int y = x; y < x + groupSize; ++y) {
+ if (cnt.merge(y, -1, Integer::sum) < 0) {
return false;
}
- cnt.put(x, cnt.get(x) - 1);
- if (cnt.get(x) == 0) {
- cnt.remove(x);
- }
}
}
}
@@ -123,17 +126,22 @@ class Solution {
class Solution {
public:
bool isNStraightHand(vector& hand, int groupSize) {
+ if (hand.size() % groupSize) {
+ return false;
+ }
+ ranges::sort(hand);
unordered_map cnt;
- for (int& v : hand) ++cnt[v];
- sort(hand.begin(), hand.end());
- for (int& v : hand) {
- if (cnt.count(v)) {
- for (int x = v; x < v + groupSize; ++x) {
- if (!cnt.count(x)) {
+ for (int x : hand) {
+ ++cnt[x];
+ }
+ for (int x : hand) {
+ if (cnt.contains(x)) {
+ for (int y = x; y < x + groupSize; ++y) {
+ if (!cnt.contains(y)) {
return false;
}
- if (--cnt[x] == 0) {
- cnt.erase(x);
+ if (--cnt[y] == 0) {
+ cnt.erase(y);
}
}
}
@@ -147,21 +155,21 @@ public:
```go
func isNStraightHand(hand []int, groupSize int) bool {
- cnt := map[int]int{}
- for _, v := range hand {
- cnt[v]++
+ if len(hand)%groupSize != 0 {
+ return false
}
sort.Ints(hand)
- for _, v := range hand {
- if _, ok := cnt[v]; ok {
- for x := v; x < v+groupSize; x++ {
- if _, ok := cnt[x]; !ok {
+ cnt := map[int]int{}
+ for _, x := range hand {
+ cnt[x]++
+ }
+ for _, x := range hand {
+ if cnt[x] > 0 {
+ for y := x; y < x+groupSize; y++ {
+ if cnt[y] == 0 {
return false
}
- cnt[x]--
- if cnt[x] == 0 {
- delete(cnt, x)
- }
+ cnt[y]--
}
}
}
@@ -172,24 +180,25 @@ func isNStraightHand(hand []int, groupSize int) bool {
#### TypeScript
```ts
-function isNStraightHand(hand: number[], groupSize: number) {
- const cnt: Record = {};
- for (const i of hand) {
- cnt[i] = (cnt[i] ?? 0) + 1;
+function isNStraightHand(hand: number[], groupSize: number): boolean {
+ if (hand.length % groupSize !== 0) {
+ return false;
}
-
- const keys = Object.keys(cnt).map(Number);
- for (const i of keys) {
- while (cnt[i]) {
- for (let j = i; j < groupSize + i; j++) {
- if (!cnt[j]) {
+ const cnt = new Map();
+ for (const x of hand) {
+ cnt.set(x, (cnt.get(x) || 0) + 1);
+ }
+ hand.sort((a, b) => a - b);
+ for (const x of hand) {
+ if (cnt.get(x)! > 0) {
+ for (let y = x; y < x + groupSize; y++) {
+ if ((cnt.get(y) || 0) === 0) {
return false;
}
- cnt[j]--;
+ cnt.set(y, cnt.get(y)! - 1);
}
}
}
-
return true;
}
```
@@ -202,11 +211,13 @@ function isNStraightHand(hand: number[], groupSize: number) {
### 方法二:有序集合
-我们也可以使用有序集合统计数组 `hand` 中每个数字出现的次数。
+与方法一类似,我们首先判断数组 $\textit{hand}$ 的长度是否能被 $\textit{groupSize}$ 整除,如果不能整除,说明无法将数组划分成若干个长度为 $\textit{groupSize}$ 的子数组,直接返回 $\text{false}$。
+
+接下来,我们用一个有序集合 $\textit{sd}$ 统计数组 $\textit{hand}$ 中每个数字出现的次数。
-接下来,循环取出有序集合中的最小值 $v$,然后枚举 $v$ 到 $v+groupSize-1$ 的每个数字,如果这些数字在有序集合中出现的次数都不为 $0$,则我们将这些数字的出现次数减 $1$,如果出现次数减 $1$ 后为 $0$,则将该数字从有序集合中删除,否则说明无法将数组划分成若干个长度为 $groupSize$ 的子数组,返回 `false`。如果可以将数组划分成若干个长度为 $groupSize$ 的子数组,则遍历结束后返回 `true`。
+然后,我们循环取出有序集合中的最小值 $x$,然后枚举 $x$ 到 $x+\textit{groupSize}-1$ 的每个数字 $y$,如果这些数字在有序集合中出现的次数都不为 $0$,则我们将这些数字的出现次数减 $1$,如果出现次数减 $1$ 后为 $0$,则将该数字从有序集合中删除,否则说明无法将数组划分成若干个长度为 $\textit{groupSize}$ 的子数组,返回 $\text{false}$。如果可以将数组划分成若干个长度为 $\textit{groupSize}$ 的子数组,则遍历结束后返回 $\text{true}$。
-时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 `hand` 的长度。
+时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $\textit{hand}$ 的长度。
@@ -215,23 +226,19 @@ function isNStraightHand(hand: number[], groupSize: number) {
```python
class Solution:
def isNStraightHand(self, hand: List[int], groupSize: int) -> bool:
- if len(hand) % groupSize != 0:
+ if len(hand) % groupSize:
return False
- sd = SortedDict()
- for h in hand:
- if h in sd:
- sd[h] += 1
- else:
- sd[h] = 1
+ cnt = Counter(hand)
+ sd = SortedDict(cnt)
while sd:
- v = sd.peekitem(0)[0]
- for i in range(v, v + groupSize):
- if i not in sd:
+ x = next(iter(sd))
+ for y in range(x, x + groupSize):
+ if y not in sd:
return False
- if sd[i] == 1:
- sd.pop(i)
+ if sd[y] == 1:
+ del sd[y]
else:
- sd[i] -= 1
+ sd[y] -= 1
return True
```
@@ -244,19 +251,18 @@ class Solution {
return false;
}
TreeMap tm = new TreeMap<>();
- for (int h : hand) {
- tm.put(h, tm.getOrDefault(h, 0) + 1);
+ for (int x : hand) {
+ tm.merge(x, 1, Integer::sum);
}
while (!tm.isEmpty()) {
- int v = tm.firstKey();
- for (int i = v; i < v + groupSize; ++i) {
- if (!tm.containsKey(i)) {
+ int x = tm.firstKey();
+ for (int y = x; y < x + groupSize; ++y) {
+ int t = tm.merge(y, -1, Integer::sum);
+ if (t < 0) {
return false;
}
- if (tm.get(i) == 1) {
- tm.remove(i);
- } else {
- tm.put(i, tm.get(i) - 1);
+ if (t == 0) {
+ tm.remove(y);
}
}
}
@@ -271,17 +277,22 @@ class Solution {
class Solution {
public:
bool isNStraightHand(vector& hand, int groupSize) {
- if (hand.size() % groupSize != 0) return false;
+ if (hand.size() % groupSize) {
+ return false;
+ }
map mp;
- for (int& h : hand) mp[h] += 1;
+ for (int x : hand) {
+ ++mp[x];
+ }
while (!mp.empty()) {
- int v = mp.begin()->first;
- for (int i = v; i < v + groupSize; ++i) {
- if (!mp.count(i)) return false;
- if (mp[i] == 1)
- mp.erase(i);
- else
- mp[i] -= 1;
+ int x = mp.begin()->first;
+ for (int y = x; y < x + groupSize; ++y) {
+ if (!mp.contains(y)) {
+ return false;
+ }
+ if (--mp[y] == 0) {
+ mp.erase(y);
+ }
}
}
return true;
@@ -296,24 +307,25 @@ func isNStraightHand(hand []int, groupSize int) bool {
if len(hand)%groupSize != 0 {
return false
}
- m := treemap.NewWithIntComparator()
- for _, h := range hand {
- if v, ok := m.Get(h); ok {
- m.Put(h, v.(int)+1)
+ tm := treemap.NewWithIntComparator()
+ for _, x := range hand {
+ if v, ok := tm.Get(x); ok {
+ tm.Put(x, v.(int)+1)
} else {
- m.Put(h, 1)
+ tm.Put(x, 1)
}
}
- for !m.Empty() {
- v, _ := m.Min()
- for i := v.(int); i < v.(int)+groupSize; i++ {
- if _, ok := m.Get(i); !ok {
- return false
- }
- if v, _ := m.Get(i); v.(int) == 1 {
- m.Remove(i)
+ for !tm.Empty() {
+ x, _ := tm.Min()
+ for y := x.(int); y < x.(int)+groupSize; y++ {
+ if v, ok := tm.Get(y); ok {
+ if v.(int) == 1 {
+ tm.Remove(y)
+ } else {
+ tm.Put(y, v.(int)-1)
+ }
} else {
- m.Put(i, v.(int)-1)
+ return false
}
}
}
@@ -325,33 +337,511 @@ func isNStraightHand(hand []int, groupSize int) bool {
```ts
function isNStraightHand(hand: number[], groupSize: number): boolean {
- const n = hand.length;
- if (n % groupSize) {
+ if (hand.length % groupSize !== 0) {
return false;
}
+ const tm = new TreeMap();
+ for (const x of hand) {
+ tm.set(x, (tm.get(x) || 0) + 1);
+ }
+ while (tm.size()) {
+ const x = tm.first()![0];
+ for (let y = x; y < x + groupSize; ++y) {
+ if (!tm.has(y)) {
+ return false;
+ }
+ if (tm.get(y)! === 1) {
+ tm.delete(y);
+ } else {
+ tm.set(y, tm.get(y)! - 1);
+ }
+ }
+ }
+ return true;
+}
- const groups: number[][] = Array.from({ length: n / groupSize }, () => []);
- hand.sort((a, b) => a - b);
+type Compare = (lhs: T, rhs: T) => number;
+
+class RBTreeNode {
+ data: T;
+ count: number;
+ left: RBTreeNode | null;
+ right: RBTreeNode | null;
+ parent: RBTreeNode | null;
+ color: number;
+ constructor(data: T) {
+ this.data = data;
+ this.left = this.right = this.parent = null;
+ this.color = 0;
+ this.count = 1;
+ }
+
+ sibling(): RBTreeNode | null {
+ if (!this.parent) return null; // sibling null if no parent
+ return this.isOnLeft() ? this.parent.right : this.parent.left;
+ }
+
+ isOnLeft(): boolean {
+ return this === this.parent!.left;
+ }
+
+ hasRedChild(): boolean {
+ return (
+ Boolean(this.left && this.left.color === 0) ||
+ Boolean(this.right && this.right.color === 0)
+ );
+ }
+}
+
+class RBTree {
+ root: RBTreeNode | null;
+ lt: (l: T, r: T) => boolean;
+ constructor(compare: Compare = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0)) {
+ this.root = null;
+ this.lt = (l: T, r: T) => compare(l, r) < 0;
+ }
+
+ rotateLeft(pt: RBTreeNode): void {
+ const right = pt.right!;
+ pt.right = right.left;
+
+ if (pt.right) pt.right.parent = pt;
+ right.parent = pt.parent;
+
+ if (!pt.parent) this.root = right;
+ else if (pt === pt.parent.left) pt.parent.left = right;
+ else pt.parent.right = right;
+
+ right.left = pt;
+ pt.parent = right;
+ }
+
+ rotateRight(pt: RBTreeNode): void {
+ const left = pt.left!;
+ pt.left = left.right;
+
+ if (pt.left) pt.left.parent = pt;
+ left.parent = pt.parent;
+
+ if (!pt.parent) this.root = left;
+ else if (pt === pt.parent.left) pt.parent.left = left;
+ else pt.parent.right = left;
+
+ left.right = pt;
+ pt.parent = left;
+ }
+
+ swapColor(p1: RBTreeNode, p2: RBTreeNode): void {
+ const tmp = p1.color;
+ p1.color = p2.color;
+ p2.color = tmp;
+ }
+
+ swapData(p1: RBTreeNode, p2: RBTreeNode): void {
+ const tmp = p1.data;
+ p1.data = p2.data;
+ p2.data = tmp;
+ }
+
+ fixAfterInsert(pt: RBTreeNode): void {
+ let parent = null;
+ let grandParent = null;
+
+ while (pt !== this.root && pt.color !== 1 && pt.parent?.color === 0) {
+ parent = pt.parent;
+ grandParent = pt.parent.parent;
+
+ /* Case : A
+ Parent of pt is left child of Grand-parent of pt */
+ if (parent === grandParent?.left) {
+ const uncle = grandParent.right;
+
+ /* Case : 1
+ The uncle of pt is also red
+ Only Recoloring required */
+ if (uncle && uncle.color === 0) {
+ grandParent.color = 0;
+ parent.color = 1;
+ uncle.color = 1;
+ pt = grandParent;
+ } else {
+ /* Case : 2
+ pt is right child of its parent
+ Left-rotation required */
+ if (pt === parent.right) {
+ this.rotateLeft(parent);
+ pt = parent;
+ parent = pt.parent;
+ }
+
+ /* Case : 3
+ pt is left child of its parent
+ Right-rotation required */
+ this.rotateRight(grandParent);
+ this.swapColor(parent!, grandParent);
+ pt = parent!;
+ }
+ } else {
+ /* Case : B
+ Parent of pt is right child of Grand-parent of pt */
+ const uncle = grandParent!.left;
+
+ /* Case : 1
+ The uncle of pt is also red
+ Only Recoloring required */
+ if (uncle != null && uncle.color === 0) {
+ grandParent!.color = 0;
+ parent.color = 1;
+ uncle.color = 1;
+ pt = grandParent!;
+ } else {
+ /* Case : 2
+ pt is left child of its parent
+ Right-rotation required */
+ if (pt === parent.left) {
+ this.rotateRight(parent);
+ pt = parent;
+ parent = pt.parent;
+ }
+
+ /* Case : 3
+ pt is right child of its parent
+ Left-rotation required */
+ this.rotateLeft(grandParent!);
+ this.swapColor(parent!, grandParent!);
+ pt = parent!;
+ }
+ }
+ }
+ this.root!.color = 1;
+ }
+
+ delete(val: T): boolean {
+ const node = this.find(val);
+ if (!node) return false;
+ node.count--;
+ if (!node.count) this.deleteNode(node);
+ return true;
+ }
+
+ deleteAll(val: T): boolean {
+ const node = this.find(val);
+ if (!node) return false;
+ this.deleteNode(node);
+ return true;
+ }
+
+ deleteNode(v: RBTreeNode): void {
+ const u = BSTreplace(v);
+
+ // True when u and v are both black
+ const uvBlack = (u === null || u.color === 1) && v.color === 1;
+ const parent = v.parent!;
+
+ if (!u) {
+ // u is null therefore v is leaf
+ if (v === this.root) this.root = null;
+ // v is root, making root null
+ else {
+ if (uvBlack) {
+ // u and v both black
+ // v is leaf, fix double black at v
+ this.fixDoubleBlack(v);
+ } else {
+ // u or v is red
+ if (v.sibling()) {
+ // sibling is not null, make it red"
+ v.sibling()!.color = 0;
+ }
+ }
+ // delete v from the tree
+ if (v.isOnLeft()) parent.left = null;
+ else parent.right = null;
+ }
+ return;
+ }
+
+ if (!v.left || !v.right) {
+ // v has 1 child
+ if (v === this.root) {
+ // v is root, assign the value of u to v, and delete u
+ v.data = u.data;
+ v.left = v.right = null;
+ } else {
+ // Detach v from tree and move u up
+ if (v.isOnLeft()) parent.left = u;
+ else parent.right = u;
+ u.parent = parent;
+ if (uvBlack) this.fixDoubleBlack(u);
+ // u and v both black, fix double black at u
+ else u.color = 1; // u or v red, color u black
+ }
+ return;
+ }
- for (let i = 0; i < n; i++) {
- let isPushed = false;
+ // v has 2 children, swap data with successor and recurse
+ this.swapData(u, v);
+ this.deleteNode(u);
+
+ // find node that replaces a deleted node in BST
+ function BSTreplace(x: RBTreeNode): RBTreeNode | null {
+ // when node have 2 children
+ if (x.left && x.right) return successor(x.right);
+ // when leaf
+ if (!x.left && !x.right) return null;
+ // when single child
+ return x.left ?? x.right;
+ }
+ // find node that do not have a left child
+ // in the subtree of the given node
+ function successor(x: RBTreeNode): RBTreeNode {
+ let temp = x;
+ while (temp.left) temp = temp.left;
+ return temp;
+ }
+ }
- for (const g of groups) {
- if (g.length === groupSize || (g.length && hand[i] - g.at(-1)! !== 1)) {
- continue;
+ fixDoubleBlack(x: RBTreeNode): void {
+ if (x === this.root) return; // Reached root
+
+ const sibling = x.sibling();
+ const parent = x.parent!;
+ if (!sibling) {
+ // No sibiling, double black pushed up
+ this.fixDoubleBlack(parent);
+ } else {
+ if (sibling.color === 0) {
+ // Sibling red
+ parent.color = 0;
+ sibling.color = 1;
+ if (sibling.isOnLeft()) this.rotateRight(parent);
+ // left case
+ else this.rotateLeft(parent); // right case
+ this.fixDoubleBlack(x);
+ } else {
+ // Sibling black
+ if (sibling.hasRedChild()) {
+ // at least 1 red children
+ if (sibling.left && sibling.left.color === 0) {
+ if (sibling.isOnLeft()) {
+ // left left
+ sibling.left.color = sibling.color;
+ sibling.color = parent.color;
+ this.rotateRight(parent);
+ } else {
+ // right left
+ sibling.left.color = parent.color;
+ this.rotateRight(sibling);
+ this.rotateLeft(parent);
+ }
+ } else {
+ if (sibling.isOnLeft()) {
+ // left right
+ sibling.right!.color = parent.color;
+ this.rotateLeft(sibling);
+ this.rotateRight(parent);
+ } else {
+ // right right
+ sibling.right!.color = sibling.color;
+ sibling.color = parent.color;
+ this.rotateLeft(parent);
+ }
+ }
+ parent.color = 1;
+ } else {
+ // 2 black children
+ sibling.color = 0;
+ if (parent.color === 1) this.fixDoubleBlack(parent);
+ else parent.color = 1;
+ }
}
+ }
+ }
- g.push(hand[i]);
- isPushed = true;
- break;
+ insert(data: T): boolean {
+ // search for a position to insert
+ let parent = this.root;
+ while (parent) {
+ if (this.lt(data, parent.data)) {
+ if (!parent.left) break;
+ else parent = parent.left;
+ } else if (this.lt(parent.data, data)) {
+ if (!parent.right) break;
+ else parent = parent.right;
+ } else break;
}
- if (!isPushed) {
+ // insert node into parent
+ const node = new RBTreeNode(data);
+ if (!parent) this.root = node;
+ else if (this.lt(node.data, parent.data)) parent.left = node;
+ else if (this.lt(parent.data, node.data)) parent.right = node;
+ else {
+ parent.count++;
return false;
}
+ node.parent = parent;
+ this.fixAfterInsert(node);
+ return true;
+ }
+
+ search(predicate: (val: T) => boolean, direction: 'left' | 'right'): T | undefined {
+ let p = this.root;
+ let result = null;
+ while (p) {
+ if (predicate(p.data)) {
+ result = p;
+ p = p[direction];
+ } else {
+ p = p[direction === 'left' ? 'right' : 'left'];
+ }
+ }
+ return result?.data;
}
- return true;
+ find(data: T): RBTreeNode | null {
+ let p = this.root;
+ while (p) {
+ if (this.lt(data, p.data)) {
+ p = p.left;
+ } else if (this.lt(p.data, data)) {
+ p = p.right;
+ } else break;
+ }
+ return p ?? null;
+ }
+
+ count(data: T): number {
+ const node = this.find(data);
+ return node ? node.count : 0;
+ }
+
+ *inOrder(root: RBTreeNode = this.root!): Generator {
+ if (!root) return;
+ for (const v of this.inOrder(root.left!)) yield v;
+ yield root.data;
+ for (const v of this.inOrder(root.right!)) yield v;
+ }
+
+ *reverseInOrder(root: RBTreeNode