diff --git a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README.md b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README.md index 0bfd0dd5f6c13..cd3f70b826d79 100644 --- a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README.md +++ b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README.md @@ -128,7 +128,9 @@ class Solution { class Solution { public: int maxHeight(vector>& cuboids) { - for (auto& c : cuboids) sort(c.begin(), c.end()); + for (auto& c : cuboids) { + sort(c.begin(), c.end()); + } sort(cuboids.begin(), cuboids.end()); int n = cuboids.size(); vector f(n); @@ -168,6 +170,33 @@ func maxHeight(cuboids [][]int) int { } ``` +```ts +function maxHeight(cuboids: number[][]): number { + for (const c of cuboids) { + c.sort((a, b) => a - b); + } + cuboids.sort((a, b) => { + if (a[0] !== b[0]) { + return a[0] - b[0]; + } + if (a[1] !== b[1]) { + return a[1] - b[1]; + } + return a[2] - b[2]; + }); + const n = cuboids.length; + const f = Array(n).fill(0); + for (let i = 0; i < n; ++i) { + for (let j = 0; j < i; ++j) { + const ok = cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2]; + if (ok) f[i] = Math.max(f[i], f[j]); + } + f[i] += cuboids[i][2]; + } + return Math.max(...f); +} +``` + ```js /** * @param {number[][]} cuboids @@ -178,12 +207,16 @@ var maxHeight = function (cuboids) { c.sort((a, b) => a - b); } cuboids.sort((a, b) => { - if (a[0] != b[0]) return a[0] - b[0]; - if (a[1] != b[1]) return a[1] - b[1]; + if (a[0] !== b[0]) { + return a[0] - b[0]; + } + if (a[1] !== b[1]) { + return a[1] - b[1]; + } return a[2] - b[2]; }); const n = cuboids.length; - const f = new Array(n).fill(0); + const f = Array(n).fill(0); for (let i = 0; i < n; ++i) { for (let j = 0; j < i; ++j) { const ok = cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2]; diff --git a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README_EN.md b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README_EN.md index 625cc2c2edc66..4ef9e3b8fc766 100644 --- a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README_EN.md +++ b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/README_EN.md @@ -124,7 +124,9 @@ class Solution { class Solution { public: int maxHeight(vector>& cuboids) { - for (auto& c : cuboids) sort(c.begin(), c.end()); + for (auto& c : cuboids) { + sort(c.begin(), c.end()); + } sort(cuboids.begin(), cuboids.end()); int n = cuboids.size(); vector f(n); @@ -164,6 +166,33 @@ func maxHeight(cuboids [][]int) int { } ``` +```ts +function maxHeight(cuboids: number[][]): number { + for (const c of cuboids) { + c.sort((a, b) => a - b); + } + cuboids.sort((a, b) => { + if (a[0] !== b[0]) { + return a[0] - b[0]; + } + if (a[1] !== b[1]) { + return a[1] - b[1]; + } + return a[2] - b[2]; + }); + const n = cuboids.length; + const f = Array(n).fill(0); + for (let i = 0; i < n; ++i) { + for (let j = 0; j < i; ++j) { + const ok = cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2]; + if (ok) f[i] = Math.max(f[i], f[j]); + } + f[i] += cuboids[i][2]; + } + return Math.max(...f); +} +``` + ```js /** * @param {number[][]} cuboids @@ -174,12 +203,16 @@ var maxHeight = function (cuboids) { c.sort((a, b) => a - b); } cuboids.sort((a, b) => { - if (a[0] != b[0]) return a[0] - b[0]; - if (a[1] != b[1]) return a[1] - b[1]; + if (a[0] !== b[0]) { + return a[0] - b[0]; + } + if (a[1] !== b[1]) { + return a[1] - b[1]; + } return a[2] - b[2]; }); const n = cuboids.length; - const f = new Array(n).fill(0); + const f = Array(n).fill(0); for (let i = 0; i < n; ++i) { for (let j = 0; j < i; ++j) { const ok = cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2]; diff --git a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.cpp b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.cpp index 73c0c4104adf6..08c60de7183c3 100644 --- a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.cpp +++ b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.cpp @@ -1,7 +1,9 @@ class Solution { public: int maxHeight(vector>& cuboids) { - for (auto& c : cuboids) sort(c.begin(), c.end()); + for (auto& c : cuboids) { + sort(c.begin(), c.end()); + } sort(cuboids.begin(), cuboids.end()); int n = cuboids.size(); vector f(n); diff --git a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.js b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.js index f8cf5773e982a..63220ad64d8d2 100644 --- a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.js +++ b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.js @@ -7,12 +7,16 @@ var maxHeight = function (cuboids) { c.sort((a, b) => a - b); } cuboids.sort((a, b) => { - if (a[0] != b[0]) return a[0] - b[0]; - if (a[1] != b[1]) return a[1] - b[1]; + if (a[0] !== b[0]) { + return a[0] - b[0]; + } + if (a[1] !== b[1]) { + return a[1] - b[1]; + } return a[2] - b[2]; }); const n = cuboids.length; - const f = new Array(n).fill(0); + const f = Array(n).fill(0); for (let i = 0; i < n; ++i) { for (let j = 0; j < i; ++j) { const ok = cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2]; diff --git a/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.ts b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.ts new file mode 100644 index 0000000000000..e85d74e3a648e --- /dev/null +++ b/solution/1600-1699/1691.Maximum Height by Stacking Cuboids/Solution.ts @@ -0,0 +1,24 @@ +function maxHeight(cuboids: number[][]): number { + for (const c of cuboids) { + c.sort((a, b) => a - b); + } + cuboids.sort((a, b) => { + if (a[0] !== b[0]) { + return a[0] - b[0]; + } + if (a[1] !== b[1]) { + return a[1] - b[1]; + } + return a[2] - b[2]; + }); + const n = cuboids.length; + const f = Array(n).fill(0); + for (let i = 0; i < n; ++i) { + for (let j = 0; j < i; ++j) { + const ok = cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2]; + if (ok) f[i] = Math.max(f[i], f[j]); + } + f[i] += cuboids[i][2]; + } + return Math.max(...f); +} diff --git a/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README.md b/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README.md index e0b51d0efacfb..4a0e93da2bbb4 100644 --- a/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README.md +++ b/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README.md @@ -60,115 +60,6 @@ 时间复杂度 $O(m \times \log m + q \times \log q)$,其中 $m$ 和 $q$ 分别为边数和查询数。 -附并查集相关介绍以及常用模板: - -并查集是一种树形的数据结构,顾名思义,它用于处理一些不交集的**合并**及**查询**问题。 它支持两种操作: - -1. 查找(Find):确定某个元素处于哪个子集,单次操作时间复杂度 $O(\alpha(n))$ -1. 合并(Union):将两个子集合并成一个集合,单次操作时间复杂度 $O(\alpha(n))$ - -其中 $\alpha$ 为阿克曼函数的反函数,其增长极其缓慢,也就是说其单次操作的平均运行时间可以认为是一个很小的常数。 - -以下是并查集的常用模板,需要熟练掌握。其中: - -- `n` 表示节点数 -- `p` 存储每个点的父节点,初始时每个点的父节点都是自己 -- `size` 只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量 -- `find(x)` 函数用于查找 $x$ 所在集合的祖宗节点 -- `union(a, b)` 函数用于合并 $a$ 和 $b$ 所在的集合 - -```python [sol1-Python3 模板] -p = list(range(n)) -size = [1] * n - -def find(x): - if p[x] != x: - # 路径压缩 - p[x] = find(p[x]) - return p[x] - - -def union(a, b): - pa, pb = find(a), find(b) - if pa == pb: - return - p[pa] = pb - size[pb] += size[pa] -``` - -```java [sol1-Java 模板] -int[] p = new int[n]; -int[] size = new int[n]; -for (int i = 0; i < n; ++i) { - p[i] = i; - size[i] = 1; -} - -int find(int x) { - if (p[x] != x) { - // 路径压缩 - p[x] = find(p[x]); - } - return p[x]; -} - -void union(int a, int b) { - int pa = find(a), pb = find(b); - if (pa == pb) { - return; - } - p[pa] = pb; - size[pb] += size[pa]; -} -``` - -```cpp [sol1-C++ 模板] -vector p(n); -iota(p.begin(), p.end(), 0); -vector size(n, 1); - -int find(int x) { - if (p[x] != x) { - // 路径压缩 - p[x] = find(p[x]); - } - return p[x]; -} - -void unite(int a, int b) { - int pa = find(a), pb = find(b); - if (pa == pb) return; - p[pa] = pb; - size[pb] += size[pa]; -} -``` - -```go [sol1-Go 模板] -p := make([]int, n) -size := make([]int, n) -for i := range p { - p[i] = i - size[i] = 1 -} - -func find(x int) int { - if p[x] != x { - // 路径压缩 - p[x] = find(p[x]) - } - return p[x] -} - -func union(a, b int) { - pa, pb := find(a), find(b) - if pa == pb { - return - } - p[pa] = pb - size[pb] += size[pa] -} -``` - ```python @@ -376,4 +267,117 @@ impl Solution { +附并查集相关介绍以及常用模板: + +并查集是一种树形的数据结构,顾名思义,它用于处理一些不交集的**合并**及**查询**问题。 它支持两种操作: + +1. 查找(Find):确定某个元素处于哪个子集,单次操作时间复杂度 $O(\alpha(n))$ +1. 合并(Union):将两个子集合并成一个集合,单次操作时间复杂度 $O(\alpha(n))$ + +其中 $\alpha$ 为阿克曼函数的反函数,其增长极其缓慢,也就是说其单次操作的平均运行时间可以认为是一个很小的常数。 + +以下是并查集的常用模板,需要熟练掌握。其中: + +- `n` 表示节点数 +- `p` 存储每个点的父节点,初始时每个点的父节点都是自己 +- `size` 只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量 +- `find(x)` 函数用于查找 $x$ 所在集合的祖宗节点 +- `union(a, b)` 函数用于合并 $a$ 和 $b$ 所在的集合 + + + +```python +p = list(range(n)) +size = [1] * n + +def find(x): + if p[x] != x: + # 路径压缩 + p[x] = find(p[x]) + return p[x] + + +def union(a, b): + pa, pb = find(a), find(b) + if pa == pb: + return + p[pa] = pb + size[pb] += size[pa] +``` + +```java +int[] p = new int[n]; +int[] size = new int[n]; +for (int i = 0; i < n; ++i) { + p[i] = i; + size[i] = 1; +} + +int find(int x) { + if (p[x] != x) { + // 路径压缩 + p[x] = find(p[x]); + } + return p[x]; +} + +void union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return; + } + p[pa] = pb; + size[pb] += size[pa]; +} +``` + +```cpp +vector p(n); +iota(p.begin(), p.end(), 0); +vector size(n, 1); + +int find(int x) { + if (p[x] != x) { + // 路径压缩 + p[x] = find(p[x]); + } + return p[x]; +} + +void unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) return; + p[pa] = pb; + size[pb] += size[pa]; +} +``` + +```go +p := make([]int, n) +size := make([]int, n) +for i := range p { + p[i] = i + size[i] = 1 +} + +func find(x int) int { + if p[x] != x { + // 路径压缩 + p[x] = find(p[x]) + } + return p[x] +} + +func union(a, b int) { + pa, pb := find(a), find(b) + if pa == pb { + return + } + p[pa] = pb + size[pb] += size[pa] +} +``` + + + diff --git a/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README_EN.md b/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README_EN.md index 1297221b79953..bc6ec4df8a81d 100644 --- a/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README_EN.md +++ b/solution/1600-1699/1697.Checking Existence of Edge Length Limited Paths/README_EN.md @@ -46,7 +46,15 @@ For the second query, there is a path (0 -> 1 -> 2) of two edges with dist ## Solutions -### Solution 1 +### Solution 1: Offline Queries + Union-Find + +According to the problem requirements, we need to judge each query $queries[i]$, that is, to determine whether there is a path with edge weight less than or equal to $limit$ between the two points $a$ and $b$ of the current query. + +The connectivity of two points can be determined by a union-find set. Moreover, since the order of queries does not affect the result, we can sort all queries in ascending order by $limit$, and also sort all edges in ascending order by edge weight. + +Then for each query, we start from the edge with the smallest weight, add all edges with weights strictly less than $limit$ to the union-find set, and then use the query operation of the union-find set to determine whether the two points are connected. + +The time complexity is $O(m \times \log m + q \times \log q)$, where $m$ and $q$ are the number of edges and queries, respectively. @@ -255,4 +263,111 @@ impl Solution { +Union-Find is a tree-like data structure that, as the name suggests, is used to handle some disjoint set **merge** and **query** problems. It supports two operations: + +1. Find: Determine which subset an element belongs to. The time complexity of a single operation is $O(\alpha(n))$. +2. Union: Merge two subsets into one set. The time complexity of a single operation is $O(\alpha(n))$. + +Here, $\alpha$ is the inverse Ackermann function, which grows extremely slowly. In other words, the average running time of its single operation can be considered a very small constant. + +Below is a common template for Union-Find, which needs to be mastered proficiently. Where: + +- `n` represents the number of nodes. +- `p` stores the parent node of each point. Initially, the parent node of each point is itself. +- `size` only makes sense when the node is an ancestor node, indicating the number of points in the set where the ancestor node is located. +- `find(x)` function is used to find the ancestor node of the set where $x$ is located. +- `union(a, b)` function is used to merge the sets where $a$ and $b$ are located. + + + +```python +p = list(range(n)) +size = [1] * n + +def find(x): + if p[x] != x: + p[x] = find(p[x]) + return p[x] + + +def union(a, b): + pa, pb = find(a), find(b) + if pa == pb: + return + p[pa] = pb + size[pb] += size[pa] +``` + +```java +int[] p = new int[n]; +int[] size = new int[n]; +for (int i = 0; i < n; ++i) { + p[i] = i; + size[i] = 1; +} + +int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; +} + +void union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return; + } + p[pa] = pb; + size[pb] += size[pa]; +} +``` + +```cpp +vector p(n); +iota(p.begin(), p.end(), 0); +vector size(n, 1); + +int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; +} + +void unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) return; + p[pa] = pb; + size[pb] += size[pa]; +} +``` + +```go +p := make([]int, n) +size := make([]int, n) +for i := range p { + p[i] = i + size[i] = 1 +} + +func find(x int) int { + if p[x] != x { + p[x] = find(p[x]) + } + return p[x] +} + +func union(a, b int) { + pa, pb := find(a), find(b) + if pa == pb { + return + } + p[pa] = pb + size[pb] += size[pa] +} +``` + + + diff --git a/solution/1600-1699/1699.Number of Calls Between Two Persons/README.md b/solution/1600-1699/1699.Number of Calls Between Two Persons/README.md index e2fb0bcb58e67..33663469bd12c 100644 --- a/solution/1600-1699/1699.Number of Calls Between Two Persons/README.md +++ b/solution/1600-1699/1699.Number of Calls Between Two Persons/README.md @@ -79,12 +79,6 @@ FROM Calls GROUP BY 1, 2; ``` - - -### 方法二 - - - ```sql # Write your MySQL query statement below SELECT diff --git a/solution/1600-1699/1699.Number of Calls Between Two Persons/README_EN.md b/solution/1600-1699/1699.Number of Calls Between Two Persons/README_EN.md index 38e8d73163f5d..37f273452dba2 100644 --- a/solution/1600-1699/1699.Number of Calls Between Two Persons/README_EN.md +++ b/solution/1600-1699/1699.Number of Calls Between Two Persons/README_EN.md @@ -77,12 +77,6 @@ FROM Calls GROUP BY 1, 2; ``` - - -### Solution 2 - - - ```sql # Write your MySQL query statement below SELECT