首先,给大家推荐一个平台,Coursera (类比国内的mooc网),你可以在上面学习诸多国外一流大学的公开课视频,各个领域的都有,涉猎范围很广。想要出国留学的小伙伴儿不妨在上面事先感受一波国外授课的氛围与模式。
言归正传,作为一名程序猿,算法实在是太重要了!即便不是一名程序员,学习一下算法编程也是很有好处的。因为,在某种层面上讲,算法是你针对计算机进行的解决问题的思想上的映射,代码就是你想法的载体,逻辑的展现形式和与计算机进行沟通的工具。随着学习的深入,你会发现好多编程的技巧其实都源于生活!学习编程就是感悟生命!当然,在某种程度上,你也可以理解为我在胡说八道!哈哈!
下面介绍一下我学习普林斯顿大学_算法公开课:Part_1的经历吧!
由于是回顾课程,所以重点放在对核心算法的理解与剖析上:
第一部分:并查集
问题描述:你可以把下面这个图整体想象成是一个地下管道通水系统。黑色的是土,白色的是空管道,蓝色的是通水的管道。
显然,水是从上往下流的,只有靠近最上边界的管道才可以通水。同时,这个通水的过程是有压力的,不知道是不是有一个水泵,还是自然现象,凡是联通的水管情况是保持一致的,即不管管道是否是逆生长,既然你们手拉手是联通的,那就是一伙儿的,要么同流合污,要么空空如也!这里有一个关键点,你在编程中会注意到:下边界不是自联通的。而上边界,你可以想象成在其上方有一个水库,凡是靠近边界的水管都有水喝,呵呵!说了这么多废话,那么问题究竟是什么呢?就是针对一大片直立的黑土地,随机的铺设管道,啥时候水管才能Percolate?Percolate啥意识呢?就是上下边界中存在至少一条联通的水流!
答案是:
mean= 0.59229975
stddev= 0.011781283036553099
95% confidence interval=[0.5899906185248356,0.5946088814751644]
就是说大概随机管道铺设覆盖率达到60%,上下边界水流就通了!
怎么样,60分及格不无道理吧!编程即生活吧!
并查集核心算法:
package unionFind;
public class SelfUN {
private int count;
private int[] parent;
//private int[] size;//记录以当前节点为根节点的子树拥有的节点总数。
public SelfUN(int n) {//节点初始化。
count = n;
parent = new int[n];
//size = new int[n];
for (int i = 0; i < n; i++) {//初始状态每个节点的父节点是其自身。
parent[i] = i;
//size[i] = 1;
}
}
public int getCount() {//获取并查集中节点总数。
return count;
}
private void validate(int p) {//节点是否有效判别。
try {
if (p < 0 || p >= count) {
throw new IllegalArgumentException("");
}
} catch (Exception e) {
System.out.println("The parameter is wrong!");
}
}
public int find(int p) {//查集
validate(p);
int root = p;
while (parent[root] != root) {//找到根节点
root = parent[root];
}
while (p != root) {//路径压缩,将除根节点以外的所有节点都直指根节点。即每一次find都是一次优化。
int tmp = parent[p];
parent[p] = root;
p = tmp;
}
return root;
}
public boolean connected(int p, int q) {//追根溯源,查看两个节点是否具有相同的根节点,进而判别是否互相联通。
return find(p) == find(q);
}
public void union(int p, int q) {//将两个节点并集,归为一类。
if (find(p) == find(q))//如果原本互联,则无需操作。
return;
/* 此处保证总是将较小的那棵树合并到较大的那棵树上,以原较大的树的根节点作为合并后的根节点的好处是使得树更均衡,也是一种路径上的优化。
* 一种极端的情况是:路径压缩过程中可以保证遍历的是节点更少的那棵树,时间复杂度在一定程度上降低了。
* if(size[p]<=size[q]) { parent[p]=q; size[q]+=size[p]; }else { parent[q]=p;
* size[p]+=size[q]; }
*/
// count--;
if (p <= q) {//此处类比大根堆,遵循某种规律实际上也是一种路径上的优化,与size的引入同理。
parent[p] = q;
} else {