Skip to content

Commit

Permalink
更新题解列表
Browse files Browse the repository at this point in the history
  • Loading branch information
itcharge committed May 20, 2024
1 parent ff355e7 commit 031da1e
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Contents/00.Introduction/04.Solutions-List.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# LeetCode 题解(已完成 859 道)
# LeetCode 题解(已完成 860 道)

| 题号 | 标题 | 题解 | 标签 | 难度 |
| :------ | :------ | :------ | :------ | :------ |
Expand Down Expand Up @@ -598,6 +598,7 @@
| 1561 | [你可以获得的最大硬币数目](https://leetcode.cn/problems/maximum-number-of-coins-you-can-get/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1561.%20%E4%BD%A0%E5%8F%AF%E4%BB%A5%E8%8E%B7%E5%BE%97%E7%9A%84%E6%9C%80%E5%A4%A7%E7%A1%AC%E5%B8%81%E6%95%B0%E7%9B%AE.md) | 贪心、数组、数学、博弈、排序 | 中等 |
| 1567 | [乘积为正数的最长子数组长度](https://leetcode.cn/problems/maximum-length-of-subarray-with-positive-product/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1567.%20%E4%B9%98%E7%A7%AF%E4%B8%BA%E6%AD%A3%E6%95%B0%E7%9A%84%E6%9C%80%E9%95%BF%E5%AD%90%E6%95%B0%E7%BB%84%E9%95%BF%E5%BA%A6.md) | 贪心、数组、动态规划 | 中等 |
| 1582 | [二进制矩阵中的特殊位置](https://leetcode.cn/problems/special-positions-in-a-binary-matrix/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1582.%20%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%9F%A9%E9%98%B5%E4%B8%AD%E7%9A%84%E7%89%B9%E6%AE%8A%E4%BD%8D%E7%BD%AE.md) | 数组、矩阵 | 简单 |
| 1584 | [连接所有点的最小费用](https://leetcode.cn/problems/min-cost-to-connect-all-points/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1584.%20%E8%BF%9E%E6%8E%A5%E6%89%80%E6%9C%89%E7%82%B9%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B4%B9%E7%94%A8.md) | 并查集、图、数组、最小生成树 | 中等 |
| 1593 | [拆分字符串使唯一子字符串的数目最大](https://leetcode.cn/problems/split-a-string-into-the-max-number-of-unique-substrings/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1593.%20%E6%8B%86%E5%88%86%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%BD%BF%E5%94%AF%E4%B8%80%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%95%B0%E7%9B%AE%E6%9C%80%E5%A4%A7.md) | 哈希表、字符串、回溯 | 中等 |
| 1595 | [连通两组点的最小成本](https://leetcode.cn/problems/minimum-cost-to-connect-two-groups-of-points/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1595.%20%E8%BF%9E%E9%80%9A%E4%B8%A4%E7%BB%84%E7%82%B9%E7%9A%84%E6%9C%80%E5%B0%8F%E6%88%90%E6%9C%AC.md) | 位运算、数组、动态规划、状态压缩、矩阵 | 困难 |
| 1603 | [设计停车系统](https://leetcode.cn/problems/design-parking-system/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1603.%20%E8%AE%BE%E8%AE%A1%E5%81%9C%E8%BD%A6%E7%B3%BB%E7%BB%9F.md) | 设计、计数、模拟 | 简单 |
Expand Down
2 changes: 1 addition & 1 deletion Contents/00.Introduction/05.Categories-List.md
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@

| 题号 | 标题 | 题解 | 标签 | 难度 |
| :------ | :------ | :------ | :------ | :------ |
| 1584 | [连接所有点的最小费用](https://leetcode.cn/problems/min-cost-to-connect-all-points/) | | 并查集、图、数组、最小生成树 | 中等 |
| 1584 | [连接所有点的最小费用](https://leetcode.cn/problems/min-cost-to-connect-all-points/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1584.%20%E8%BF%9E%E6%8E%A5%E6%89%80%E6%9C%89%E7%82%B9%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B4%B9%E7%94%A8.md) | 并查集、图、数组、最小生成树 | 中等 |
| 1631 | [最小体力消耗路径](https://leetcode.cn/problems/path-with-minimum-effort/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1631.%20%E6%9C%80%E5%B0%8F%E4%BD%93%E5%8A%9B%E6%B6%88%E8%80%97%E8%B7%AF%E5%BE%84.md) | 深度优先搜索、广度优先搜索、并查集、数组、二分查找、矩阵、堆(优先队列) | 中等 |
| 0778 | [水位上升的泳池中游泳](https://leetcode.cn/problems/swim-in-rising-water/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/0778.%20%E6%B0%B4%E4%BD%8D%E4%B8%8A%E5%8D%87%E7%9A%84%E6%B3%B3%E6%B1%A0%E4%B8%AD%E6%B8%B8%E6%B3%B3.md) | 深度优先搜索、广度优先搜索、并查集、数组、二分查找、矩阵、堆(优先队列) | 困难 |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| 题号 | 标题 | 题解 | 标签 | 难度 |
| :------ | :------ | :------ | :------ | :------ |
| 1584 | [连接所有点的最小费用](https://leetcode.cn/problems/min-cost-to-connect-all-points/) | | 并查集、图、数组、最小生成树 | 中等 |
| 1584 | [连接所有点的最小费用](https://leetcode.cn/problems/min-cost-to-connect-all-points/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1584.%20%E8%BF%9E%E6%8E%A5%E6%89%80%E6%9C%89%E7%82%B9%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B4%B9%E7%94%A8.md) | 并查集、图、数组、最小生成树 | 中等 |
| 1631 | [最小体力消耗路径](https://leetcode.cn/problems/path-with-minimum-effort/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/1631.%20%E6%9C%80%E5%B0%8F%E4%BD%93%E5%8A%9B%E6%B6%88%E8%80%97%E8%B7%AF%E5%BE%84.md) | 深度优先搜索、广度优先搜索、并查集、数组、二分查找、矩阵、堆(优先队列) | 中等 |
| 0778 | [水位上升的泳池中游泳](https://leetcode.cn/problems/swim-in-rising-water/) | [Python](https://github.com/itcharge/LeetCode-Py/blob/main/Solutions/0778.%20%E6%B0%B4%E4%BD%8D%E4%B8%8A%E5%8D%87%E7%9A%84%E6%B3%B3%E6%B1%A0%E4%B8%AD%E6%B8%B8%E6%B3%B3.md) | 深度优先搜索、广度优先搜索、并查集、数组、二分查找、矩阵、堆(优先队列) | 困难 |

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,4 @@
### 11. 附加内容

- [内容完成时间线](./Contents/Others/Update-Time.md)
### [12. LeetCode 题解(已完成 859 道)](./Contents/00.Introduction/04.Solutions-List.md)
### [12. LeetCode 题解(已完成 860 道)](./Contents/00.Introduction/04.Solutions-List.md)
171 changes: 171 additions & 0 deletions Solutions/1584. 连接所有点的最小费用.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# [1584. 连接所有点的最小费用](https://leetcode.cn/problems/min-cost-to-connect-all-points/)

- 标签:并查集、图、数组、最小生成树
- 难度:中等

## 题目链接

- [1584. 连接所有点的最小费用 - 力扣](https://leetcode.cn/problems/min-cost-to-connect-all-points/)

## 题目大意

**描述**:给定一个 $points$ 数组,表示 2D 平面上的一些点,其中 $points[i] = [x_i, y_i]$。

链接点 $[x_i, y_i]$ 和点 $[x_j, y_j]$ 的费用为它们之间的 **曼哈顿距离**:$|x_i - x_j| + |y_i - y_j|$。其中 $|val|$ 表示 $val$ 的绝对值。

**要求**:返回将所有点连接的最小总费用。

**说明**

- 只有任意两点之间有且仅有一条简单路径时,才认为所有点都已连接。
- $1 \le points.length \le 1000$。
- $-10^6 \le x_i, y_i \le 10^6$。
- 所有点 $(x_i, y_i)$ 两两不同。

**示例**

- 示例 1:

![](https://assets.leetcode.com/uploads/2020/08/26/d.png)

![](https://assets.leetcode.com/uploads/2020/08/26/c.png)

```python
输入:points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
输出:20
解释:我们可以按照上图所示连接所有点得到最小总费用,总费用为 20
注意到任意两个点之间只有唯一一条路径互相到达。
```

- 示例 2:

```python
输入:points = [[3,12],[-2,5],[-4,1]]
输出:18
```

## 解题思路

将所有点之间的费用看作是边,则所有点和边可以看作是一个无向图。每两个点之间都存在一条无向边,边的权重为两个点之间的曼哈顿距离。将所有点连接的最小总费用,其实就是求无向图的最小生成树。对此我们可以使用 Prim 算法或者 Kruskal 算法。

### 思路 1:Prim 算法

每次选择最短边来扩展最小生成树,从而保证生成树的总权重最小。算法通过不断扩展小生成树的顶点集合 $MST$,逐步构建出最小生成树。

### 思路 1:代码

```Python
class Solution:
def distance(self, point1, point2):
return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])

def Prim(self, points, start):
size = len(points)
vis = set()
dis = [float('inf') for _ in range(size)]

ans = 0 # 最小生成树的边权值
dis[start] = 0 # 起始位置到起始位置的边权值初始化为 0

for i in range(1, size):
dis[i] = self.distance(points[start], points[i])
vis.add(start)

for _ in range(size - 1): # 进行 n 轮迭代
min_dis = float('inf')
min_dis_i = -1
for i in range(size):
if i not in vis and dis[i] < min_dis:
min_dis = dis[i]
min_dis_i = i
if min_dis_i == -1:
return -1

ans += min_dis
vis.add(min_dis_i)


for i in range(size):
if i not in vis:
dis[i] = min(dis[i], self.distance(points[i], points[min_dis_i]))

return ans

def minCostConnectPoints(self, points: List[List[int]]) -> int:
return self.Prim(points, 0)
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n^2)$。
- **空间复杂度**:$O(n^2)$。

### 思路 2:Kruskal 算法

通过依次选择权重最小的边并判断其两个端点是否连接在同一集合中,从而逐步构建最小生成树。这个过程保证了最终生成的树是无环的,并且总权重最小。

### 思路 2:代码

```python
class UnionFind:

def __init__(self, n):
self.parent = [i for i in range(n)]
self.count = n

def find(self, x):
while x != self.parent[x]:
self.parent[x] = self.parent[self.parent[x]]
x = self.parent[x]
return x

def union(self, x, y):
root_x = self.find(x)
root_y = self.find(y)
if root_x == root_y:
return

self.parent[root_x] = root_y
self.count -= 1

def is_connected(self, x, y):
return self.find(x) == self.find(y)


class Solution:
def Kruskal(self, edges, size):
union_find = UnionFind(size)

edges.sort(key=lambda x: x[2])

ans, cnt = 0, 0
for x, y, dist in edges:
if union_find.is_connected(x, y):
continue
ans += dist
cnt += 1
union_find.union(x, y)
if cnt == size - 1:
return ans
return ans

def minCostConnectPoints(self, points: List[List[int]]) -> int:
size = len(points)
edges = []
for i in range(size):
xi, yi = points[i]
for j in range(i + 1, size):
xj, yj = points[j]
dist = abs(xi - xj) + abs(yi - yj)
edges.append([i, j, dist])

ans = self.Kruskal(edges, size)
return ans

```

### 思路 2:复杂度分析

- **时间复杂度**:$O(m \times \log(n))$。其中 $m$ 为边数,$n$ 为节点数,本题中 $m = n^2$。
- **空间复杂度**:$O(n^2)$。

55 changes: 55 additions & 0 deletions Templates/08.Graph/Graph-Kruskal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
class UnionFind:

def __init__(self, n):
self.parent = [i for i in range(n)]
self.count = n

def find(self, x):
while x != self.parent[x]:
self.parent[x] = self.parent[self.parent[x]]
x = self.parent[x]
return x

def union(self, x, y):
root_x = self.find(x)
root_y = self.find(y)
if root_x == root_y:
return

self.parent[root_x] = root_y
self.count -= 1

def is_connected(self, x, y):
return self.find(x) == self.find(y)


class Solution:
def Kruskal(self, edges, size):
union_find = UnionFind(size)

edges.sort(key=lambda x: x[2])

res, cnt = 0, 1
for x, y, dist in edges:
if union_find.is_connected(x, y):
continue
ans += dist
cnt += 1
union_find.union(x, y)
if cnt == size - 1:
return ans
return ans

def minCostConnectPoints(self, points: List[List[int]]) -> int:
size = len(points)
edges = []
for i in range(size):
xi, yi = points[i]
for j in range(i + 1, size):
xj, yj = points[j]
dist = abs(xi - xj) + abs(yi - yj)
edges.append([i, j, dist])

ans = Solution().Kruskal(edges, size)
return ans

4 changes: 2 additions & 2 deletions Templates/08.Graph/Graph-Prim.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Solution:
# graph 为图的邻接矩阵,start 为起始顶点
def prim(self, graph, start):
def Prim(self, graph, start):
size = len(graph)
vis = set()
dist = [float('inf') for _ in range(size)]
Expand Down Expand Up @@ -44,4 +44,4 @@ def prim(self, graph, start):
graph[j][i] = dist


print(Solution().prim(graph))
print(Solution().Prim(graph))

0 comments on commit 031da1e

Please sign in to comment.