auto commit
This commit is contained in:
parent
480ce3db3c
commit
9ee0daf60a
74
notes/算法.md
74
notes/算法.md
|
@ -28,6 +28,7 @@
|
|||
* [红黑二叉查找树](#红黑二叉查找树)
|
||||
* [散列表](#散列表)
|
||||
* [应用](#应用)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
|
@ -41,7 +42,7 @@ N<sup>3</sup>/6-N<sup>2</sup>/2+N/3 \~ N<sup>3</sup>/6。使用 \~f(N) 来表示
|
|||
|
||||
### 2. 增长数量级
|
||||
|
||||
N<sup>3</sup>/6-N<sup>2</sup>/2+N/3 的增长数量级为 O(N<sup>3</sup>)。增长数量级将算法与它的实现隔离开来,一个算法的增长数量级为 O(N<sup>3</sup>)与它是否用 Java 实现,是否运行于特定计算机上无关。
|
||||
N<sup>3</sup>/6-N<sup>2</sup>/2+N/3 的增长数量级为 O(N<sup>3</sup>)。增长数量级将算法与它的实现隔离开来,一个算法的增长数量级为 O(N<sup>3</sup>) 与它是否用 Java 实现,是否运行于特定计算机上无关。
|
||||
|
||||
### 3. 内循环
|
||||
|
||||
|
@ -57,13 +58,13 @@ ThreeSum 用于统计一个数组中三元组的和为 0 的数量。
|
|||
|
||||
```java
|
||||
public class ThreeSum {
|
||||
public static int count(int[] a) {
|
||||
int N = a.length;
|
||||
public int count(int[] nums) {
|
||||
int N = nums.length;
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = i + 1; j < N; j++) {
|
||||
for (int k = j + 1; k < N; k++) {
|
||||
if (a[i] + a[j] + a[k] == 0) {
|
||||
if (nums[i] + nums[j] + nums[k] == 0) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +75,7 @@ public class ThreeSum {
|
|||
}
|
||||
```
|
||||
|
||||
该算法的内循环为 if (a[i] + a[j] + a[k] == 0) 语句,总共执行的次数为 N(N-1)(N-2) = N<sup>3</sup>/6 - N<sup>2</sup>/2 + N/3,因此它的近似执行次数为 \~N<sup>3</sup>/6,增长数量级为 N<sup>3</sup>。
|
||||
该算法的内循环为 if(a[i]+a[j]+a[k]==0) 语句,总共执行的次数为 N(N-1)(N-2) = N<sup>3</sup>/6-N<sup>2</sup>/2+N/3,因此它的近似执行次数为 \~N<sup>3</sup>/6,增长数量级为 N<sup>3</sup>。
|
||||
|
||||
<font size=4> **改进** </font></br>
|
||||
|
||||
|
@ -84,21 +85,31 @@ public class ThreeSum {
|
|||
|
||||
```java
|
||||
public class ThreeSumFast {
|
||||
public static int count(int[] a) {
|
||||
Arrays.sort(a);
|
||||
int N = a.length;
|
||||
public int count(int[] nums) {
|
||||
Arrays.sort(nums);
|
||||
int N = nums.length;
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = i + 1; j < N; j++) {
|
||||
// rank() 方法返回元素在数组中的下标,如果元素不存在,这里会返回 -1。
|
||||
// 应该注意这里的下标必须大于 j,否则会重复统计。
|
||||
if (BinarySearch.rank(-a[i] - a[j], a) > j) {
|
||||
if (binarySearch(nums, -nums[i] - nums[j]) > j) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
private int binarySearch(int[] nums, int target) {
|
||||
int l = 0, h = nums.length - 1;
|
||||
while (l <= h) {
|
||||
int m = l + (h - l) / 2;
|
||||
if (nums[m] == target) return m;
|
||||
else if (nums[m] < target) h = m - 1;
|
||||
else l = m + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -109,7 +120,7 @@ public class ThreeSumFast {
|
|||
例如对于暴力方法的 ThreeSum 算法,近似时间为 \~N<sup>3</sup>/6。进行如下实验:多次运行该算法,每次取的 N 值为前一次的两倍,统计每次执行的时间,并统计本次运行时间与前一次运行时间的比值,得到如下结果:
|
||||
|
||||
| N | Time | Ratio |
|
||||
| --- | --- | --- |
|
||||
| :---: | :---: | :---: |
|
||||
| 250 | 0.0 | 2.7 |
|
||||
| 500 | 0.0 | 4.8 |
|
||||
| 1000 | 0.1 | 6.9 |
|
||||
|
@ -305,17 +316,21 @@ public class Queue<Item> {
|
|||
|
||||
用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。
|
||||
|
||||
<div align="center"> <img src="../pics//7e9d0ef2-acd8-44c0-a76b-f0d2f5e76738.png" width="300"/> </div><br>
|
||||
<div align="center"> <img src="../pics//dc752c5b-bb59-4616-bf9c-21276690a24d.png"/> </div><br>
|
||||
|
||||
<font size=4> **API** </font> <br>
|
||||
|
||||
<div align="center"> <img src="../pics//867abc3c-8403-43ef-8847-c1fea32996a5.png" width="800"/> </div><br>
|
||||
| 方法 | 描述 |
|
||||
| ---: | :--- |
|
||||
| UF(int N) | 构造一个大小为 N 的并查集 |
|
||||
| void union(int p, int q) | 连接 p 和 q 节点 |
|
||||
| int find(int p) | 查找 p 所在的连通分量 |
|
||||
| boolean connected(int p, int q) | 判断 p 和 q 节点是否连通 |
|
||||
|
||||
<font size=4> **基本数据结构** </font> <br>
|
||||
|
||||
```java
|
||||
public class UF {
|
||||
// 使用 id 数组来保存点的连通信息
|
||||
private int[] id;
|
||||
|
||||
public UF(int N) {
|
||||
|
@ -333,9 +348,13 @@ public class UF {
|
|||
|
||||
## quick-find
|
||||
|
||||
保证在同一连通分量的所有节点的 id 值相等。
|
||||
可以快速进行 find 操作,即可以快速判断两个节点是否连通。
|
||||
|
||||
这种方法可以快速取得一个节点的 id 值,并且判断两个节点是否连通。但是 union 的操作代价却很高,需要将其中一个连通分量中的所有节点 id 值都修改为另一个节点的 id 值。
|
||||
同一连通分量的所有节点的 id 值相等。
|
||||
|
||||
但是 union 操作代价却很高,需要将其中一个连通分量中的所有节点 id 值都修改为另一个节点的 id 值。
|
||||
|
||||
<div align="center"> <img src="../pics//0120d24f-58a2-4848-afff-ce2b76d38ffc.png"/> </div><br>
|
||||
|
||||
```java
|
||||
public int find(int p) {
|
||||
|
@ -354,9 +373,11 @@ public class UF {
|
|||
|
||||
## quick-union
|
||||
|
||||
在 union 时只将节点的 id 值指向另一个节点 id 值,不直接用 id 来存储所属的连通分量。这样就构成一个倒置的树形结构,应该注意的是根节点需要指向自己。查找一个节点所属的连通分量时,要一直向上查找直到根节点,并使用根节点的 id 值作为本连通分量的 id 值。
|
||||
可以快速进行 union 操作,只需要修改一个节点的 id 值即可。
|
||||
|
||||
<div align="center"> <img src="../pics//ae1f3f27-cb47-436d-b8a2-185618851b57.png" width="600"/> </div><br>
|
||||
但是 find 操作开销很大,因为同一个连通分量的节点 id 值不同,id 值只是用来指向另一个节点。因此需要一段进行查找操作,直到找到最上层的节点。
|
||||
|
||||
<div align="center"> <img src="../pics//d645d71f-007e-4228-8311-6b1fb61fb232.png"/> </div><br>
|
||||
|
||||
```java
|
||||
public int find(int p) {
|
||||
|
@ -374,7 +395,7 @@ public class UF {
|
|||
|
||||
这种方法可以快速进行 union 操作,但是 find 操作和树高成正比,最坏的情况下树的高度为触点的数目。
|
||||
|
||||
<div align="center"> <img src="../pics//dcbd1473-96c3-4ace-8b69-2c9342615e7e.png" width="300"/> </div><br>
|
||||
<div align="center"> <img src="../pics//bfbb11e2-d208-4efa-b97b-24cd40467cd8.png"/> </div><br>
|
||||
|
||||
## 加权 quick-union
|
||||
|
||||
|
@ -382,7 +403,7 @@ public class UF {
|
|||
|
||||
理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。
|
||||
|
||||
<div align="center"> <img src="../pics//7f9a9342-1491-436d-bdd2-0fa94eb0e4f1.png" width="500"/> </div><br>
|
||||
<div align="center"> <img src="../pics//095720ee-84b3-42ff-af71-70ceb6a2f4a3.png"/> </div><br>
|
||||
|
||||
```java
|
||||
public class WeightedQuickUnionUF {
|
||||
|
@ -429,7 +450,12 @@ public class WeightedQuickUnionUF {
|
|||
|
||||
## 各种 union-find 算法的比较
|
||||
|
||||
<div align="center"> <img src="../pics//cae894a9-2424-4de4-ab41-c15d7054a5e7.png" width="800"/> </div><br>
|
||||
| 算法 | union | find |
|
||||
| :---: | :---: | :---: |
|
||||
| quick-find | N | 1 |
|
||||
| quick-union | 树高 | 树高 |
|
||||
| 加权 quick-union | lgN | lgN |
|
||||
| 路径压缩的加权 quick-union | 非常接近 1 | 非常接近 1 |
|
||||
|
||||
# 四、排序
|
||||
|
||||
|
@ -1596,3 +1622,7 @@ public class SparseVector {
|
|||
}
|
||||
```
|
||||
|
||||
# 参考资料
|
||||
|
||||
- Sedgewick R. Algorithms[M]. Pearson Education India, 1988.
|
||||
|
||||
|
|
BIN
pics/0120d24f-58a2-4848-afff-ce2b76d38ffc.png
Normal file
BIN
pics/0120d24f-58a2-4848-afff-ce2b76d38ffc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
BIN
pics/095720ee-84b3-42ff-af71-70ceb6a2f4a3.png
Normal file
BIN
pics/095720ee-84b3-42ff-af71-70ceb6a2f4a3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png
Normal file
BIN
pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
BIN
pics/d645d71f-007e-4228-8311-6b1fb61fb232.png
Normal file
BIN
pics/d645d71f-007e-4228-8311-6b1fb61fb232.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
pics/dc752c5b-bb59-4616-bf9c-21276690a24d.png
Normal file
BIN
pics/dc752c5b-bb59-4616-bf9c-21276690a24d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Loading…
Reference in New Issue
Block a user