五大算法的理解
1.回溯算法:来一个简单直白的伪码
path;
for e in list{
// 前进一步
path.push(e);
{...} // 探索
// 再退回去
paht.pop(e);
}
可以看到,回溯算法和stack有很深的关系,典型的回溯算法如打印所有根节点到叶子节点的路径。
public void dfs(TreeNode node,Stack<Node> path){
// 找到一条路
if(node==null){
print(path);
return;
}
path.push(node.left);
dfs(node.left,path);
path.pop(node.left);
// 更新自己所在位置和走过的路径
path.push(node.right,path);
dfs(node.right,path);
}
还有经典的n皇后问题,回溯算法简单,但是其时间复杂度约是pow(M,n)级别, 爆炸型增长,当n很大时,往往会超时,或者栈溢出。这是在回溯算法中,没有充分使用图中的其他信息,或者按照一定的策略去搜索,比如迪杰特斯拉算法。
for 选择 in 选择列表:
# 做选择
将该选择从选择列表移除
路径.add(选择)
backtrack(路径, 选择列表)
# 撤销选择
路径.remove(选择)
将该选择再加入选择列表
2.动态规划算法:也叫查表法,其实就是找到从小规模到大规模的递推公式。典型的是背包问题,看一下动态规划的简单例子:计算斐波那契数列
f(n) = f(n-1) +f(n-2)
f(5) = f(4) + f(3) ;
动态规划可以简单理解为求递推公式。在具体的程序求解问题中,可以使用函数递归,也可以使用数组迭代,优先使用迭代,这个一般会更快,并且能够处理重叠子问题。
3.分治算法:分治的思想在生活中随处可见,都是将大问题划分为小问题,比如全国行政区的划分,分子的组成等。分治的核心就是划分子问题,使划分的各个子部分不会互 相影响。 典型的如快速排序。
QUICKSORT(A, p, r)
if p < r //仅当区间长度大于1才开始排序
then q ← PARTITION(A, p, r) //选取pivot主元
QUICKSORT(A, p, q - 1) //对左子序列排序
QUICKSORT(A, q + 1, r) //对右子序列排序
PARTITION(A, p, r)
x ← A[r]
i ← p - 1
for j ← p to r - 1
do if A[j] ≤ x
then i ← i + 1
exchange A[i] ←→ A[j]
// 这个就很奇怪
exchange A[i + 1] ←→ A[r]
return i + 1
// 这个总是在pivot预留一个,用于交换,节省空间。
// 快速排序算法的思想非常简单,但是就是PARTITION方法不好理解
// do--if就是if
//思想: 使用j作为指针,去遍历所有的元素,然后将小于pivot的元素放在左边,但是为了//保证不占用空间,pivot也要又移。
参考书籍:《算法设计》
《计算机程序的构造和解释》
日进有功