diff --git a/notes/算法.md b/notes/算法.md
index 97c61324..b0d03d7a 100644
--- a/notes/算法.md
+++ b/notes/算法.md
@@ -28,6 +28,7 @@
* [红黑二叉查找树](#红黑二叉查找树)
* [散列表](#散列表)
* [应用](#应用)
+* [参考资料](#参考资料)
@@ -41,7 +42,7 @@ N3/6-N2/2+N/3 \~ N3/6。使用 \~f(N) 来表示
### 2. 增长数量级
-N3/6-N2/2+N/3 的增长数量级为 O(N3)。增长数量级将算法与它的实现隔离开来,一个算法的增长数量级为 O(N3)与它是否用 Java 实现,是否运行于特定计算机上无关。
+N3/6-N2/2+N/3 的增长数量级为 O(N3)。增长数量级将算法与它的实现隔离开来,一个算法的增长数量级为 O(N3) 与它是否用 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) = N3/6 - N2/2 + N/3,因此它的近似执行次数为 \~N3/6,增长数量级为 N3。
+该算法的内循环为 if(a[i]+a[j]+a[k]==0) 语句,总共执行的次数为 N(N-1)(N-2) = N3/6-N2/2+N/3,因此它的近似执行次数为 \~N3/6,增长数量级为 N3。
**改进**
@@ -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 算法,近似时间为 \~N3/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- {
用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。
-
+
**API**
-
+| 方法 | 描述 |
+| ---: | :--- |
+| 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 节点是否连通 |
**基本数据结构**
```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 值。
+
+
```java
public int find(int p) {
@@ -354,9 +373,11 @@ public class UF {
## quick-union
-在 union 时只将节点的 id 值指向另一个节点 id 值,不直接用 id 来存储所属的连通分量。这样就构成一个倒置的树形结构,应该注意的是根节点需要指向自己。查找一个节点所属的连通分量时,要一直向上查找直到根节点,并使用根节点的 id 值作为本连通分量的 id 值。
+可以快速进行 union 操作,只需要修改一个节点的 id 值即可。
-
+但是 find 操作开销很大,因为同一个连通分量的节点 id 值不同,id 值只是用来指向另一个节点。因此需要一段进行查找操作,直到找到最上层的节点。
+
+
```java
public int find(int p) {
@@ -374,7 +395,7 @@ public class UF {
这种方法可以快速进行 union 操作,但是 find 操作和树高成正比,最坏的情况下树的高度为触点的数目。
-
+
## 加权 quick-union
@@ -382,7 +403,7 @@ public class UF {
理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。
-
+
```java
public class WeightedQuickUnionUF {
@@ -429,7 +450,12 @@ public class WeightedQuickUnionUF {
## 各种 union-find 算法的比较
-
+| 算法 | 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.
+
diff --git a/pics/0120d24f-58a2-4848-afff-ce2b76d38ffc.png b/pics/0120d24f-58a2-4848-afff-ce2b76d38ffc.png
new file mode 100644
index 00000000..7b5db630
Binary files /dev/null and b/pics/0120d24f-58a2-4848-afff-ce2b76d38ffc.png differ
diff --git a/pics/095720ee-84b3-42ff-af71-70ceb6a2f4a3.png b/pics/095720ee-84b3-42ff-af71-70ceb6a2f4a3.png
new file mode 100644
index 00000000..57e4309b
Binary files /dev/null and b/pics/095720ee-84b3-42ff-af71-70ceb6a2f4a3.png differ
diff --git a/pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png b/pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png
new file mode 100644
index 00000000..b9d9dba2
Binary files /dev/null and b/pics/bfbb11e2-d208-4efa-b97b-24cd40467cd8.png differ
diff --git a/pics/d645d71f-007e-4228-8311-6b1fb61fb232.png b/pics/d645d71f-007e-4228-8311-6b1fb61fb232.png
new file mode 100644
index 00000000..912476d1
Binary files /dev/null and b/pics/d645d71f-007e-4228-8311-6b1fb61fb232.png differ
diff --git a/pics/dc752c5b-bb59-4616-bf9c-21276690a24d.png b/pics/dc752c5b-bb59-4616-bf9c-21276690a24d.png
new file mode 100644
index 00000000..66e77b6d
Binary files /dev/null and b/pics/dc752c5b-bb59-4616-bf9c-21276690a24d.png differ