前言:容易让人理解的文章行文方式应该是从特殊到一般也即从具体例子到抽象理论的过程。这里反其道而行,让别人容易读懂不是本文的主要目的,主要目的是仅作为自己阅读的总结以备忘。
更多可参阅 labuladong算法总结 (或这个)。
-------------
总纲!!
计算机算法的本质是穷举,穷举有两个关键难点:无遗漏、无冗余:遗漏,会直接导致答案出错;冗余,会拖慢算法的运行速度;因此,对于一道算法题通常需要考虑的是如何穷举(即无遗漏地穷举所有可能解)及如何聪明地穷举(即做到无冗余的计算)。不同类型的题目,难点是不同的,有的题目难在「如何穷举」,有的题目难在「如何聪明地穷举」。
如何穷举,一般是递归类问题,回溯算法、动态规划算法等本质都是穷举。
如何聪明地穷举,一些常用的非递归算法技巧,都可归为此类,例如动态规划的备忘录、并查集算法、贪心算法、双指针、滑动窗口算法、前缀和、查分数组等等。详见labuladong刷题新的之一些常用的算法技巧。
-------------
DFS、BFS
DFS:本质就是回溯算法,见后文。
BFS:见labuladong BFS算法解题套路框架、二叉树、多叉树、图的BFS类比演变。BFS算法框架伪代码:
//BFS算法框架 // 计算从起点 start 到终点 target 的最近距离 int BFS(Node start, Node target) { Queue<Node> q; // 核心数据结构 Set<Node> visited; // 避免走回头路 q.offer(start); // 将起点加入队列 visited.add(start); int step = 0; // 记录扩散的步数 while (q not empty) { int sz = q.size(); /* 将当前队列中的所有节点向四周扩散 */ for (int i = 0; i < sz; i++) { Node cur = q.poll(); //visited.add(cur);//也可将visit操作放这,另两处就不用了,这样更简洁 /* 划重点:这里判断是否到达终点 */ if (cur is target) return step; /* 将 cur 的相邻节点加入队列 */ for (Node x : cur.adj()) { if (x not in visited) { q.offer(x); visited.add(x); } } } /* 划重点:更新步数在这里 */ step++; } }