枚举法
枚举法,本质上就是搜索算法。
- 枚举也称作穷举,指的是从问题所有可能的解的集合中一一枚举各元素。
- 用题目中给定的检验条件判定哪些是无用的,哪些是有用的。能使命题成立。即为其解。
- 优点:算法简单,在局部地方使用枚举法,效果十分的好
- 缺点:运算量过大,当问题的规模变大的时候,循环的阶数越大,执行速度越慢。
例题 1:
AB*A=CCC 求其所有的可能性。
解法:
枚举所有的A和B,两重循环1-9加判断,81次运行即可完成。如果还要优化枚举A的循环可以从3开始。
拓展一下:AA*AB=CCBB且A*B=CD。
DFS
学名:深度优先搜索。
用途:1.通过遍历所有路径,来判断两点之间是否连通。(最常用)
2.因为要走遍所有可能路径,所以也可以记录 能够到达的 位置 的个数。
特点:一搜到底。即走遍所有可能的路径。
难点:如何将题目抽象成一张
例题:
给出4个1到13的数,计算24点。
解法:
进行dfs,找能达到24点的方法。
BFS
定义:
广度优先算法(Breadth-First-Search),简称BFS,是一种图形搜索演算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点,如果发现目标,则演算终止。
算法分析:
BFS是一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
链表
链表是由有限个节点通过指针线性链接所形成的一种线性数据结构,每个节点包括两部分:数据域和指针域。数据域存储数据,指针域存储指针变量,用该指针变量来存储下一个节点所在的内存地址,从而可以利用该指针来访问下一个节点。
栈
栈是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
队列
队列是一种操作受限的线性表,其限制条件为允许在表的一端进行插入,而在表的另一端进行删除。插入的一端叫做队尾,删除的一端叫做队头。向队列中插入新元素的行为称为进队,从队列中删除元素的行为称为出队。
队列的特点是先进先出。举例:火车从山洞一端开进,从山洞另一端开出,车厢好比一个个元素,最先进入山洞的车厢先出,后进山洞的车厢后出。
堆
堆分为小根堆和大根堆两种。对于一个小根堆,它是具有如下特性的一棵完全二叉树:
(1)若树根结点存在左孩子,则根结点的值小于等于左孩子结点的值。
(2)若树根结点存在右孩子,则根结点的值也小于等于右孩子结点的值。
(3)以左、右孩子为根的子树又各是一个堆。
大根堆的定义与上述类似,只要把条件“小于等于”改为“大于等于”就可以了。由堆的定义可知,若一棵完全二叉树是堆,则该树中以每个结点为根的子树也都是一个堆。
Hash
其实吧,这个哈希,我听了老半天都没听懂,大概是老师讲的太好了我的理解能力不够吧。。。。。。所以这个就暂且跳过。
贪心&分治
一.贪心
概念
贪心算法的基本思想
求解最优化问题的算法包含一系列步骤,每一步都有一组选择,作出在当前看来最好的选择,希望通过作出局部最优选择达到全 局最优选择。
贪心算法不一定总产生最优解,贪心算法是否产生优化解,需严格证明
贪心算法产生最优解的条件:最优子结构、贪心选择性
最优子结构
当一个问题的最优解包含子问题的最优解时,称这个问题具有最优子结构
贪心选择性
当一个问题的全局最优解可以通过局部最优解得到,称这个问题具有贪心选择性
证明思路:
假定首选元素不是贪心选择所要的元素,证明将首元素替换成贪心选择所需元素,依然得到最优解。数学归纳法证明每一步均可通过贪心选择得到最优解
动态规划和贪心算法的区别
动态规划方法可用的条件:最优子结构、子问题重叠性
贪心算法产生最优解的条件:最优子结构、贪心选择性
适用贪心算法时,动态规划可能不适用。适用动态规划时,贪心算法可能不适用。
动态规划和贪心算法比较容易混淆,我的理解是动态规划是计算所有的子问题,每执行完一个步骤可能会产生多个子问题,而贪心算法则是保证每次需要解决的子问题只有一个,只需选择当下看上去最优的选择。
适用贪心思想的算法:活动选择问题、哈夫曼编码问题、最小生成树问题、单源最短路径问题等
二.分治
概念
分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
设计过程
Divide:整个问题划分为多个子问题
Conquer:求解各子问题(递归调用子问题的算法)
Combine:合并子问题的解, 形成原始问题的解
分析过程
建立递归方程
T(n)= aT(n/b)+D(n)+C(n)
Divide时间复杂度:D(n)
Conquer时间复杂度:aT(n/b)
Combine:C(n)
当n<c, T(n)=θ(1)
递归方程求解
与动态规划的区别是划分的子问题不相关(不存在公共子问题),而动态规划划分的子问题是相关性越大越好(存在公共子问题)。
分治法的关键是算法的Combine。究竟应该怎样合并,目前没有统一的模式,因此需要对具体问题进行具体分析,以得出比较好的合并算法。
适用分治思想的算法:二分搜索、归并排序、快速排序、大整数乘法、Strassen矩阵乘法、汉诺塔、第K小元素、最近点对、快速傅里叶变换等。
拿到一个问题,首先想想问题的规模是否可以缩小到一定的规模就可以较容易地解决,是否具有最优子结构性质,是否合并问题分解出的子问题的解可以得到问题的解,子问题之间是否相互独立。
动态规划
动态规划这种东西简直就是丧心病狂,我听了半天就像听催眠曲一样,越听越想睡觉,唉。。。。。。
概念
与分治法类似,动态规划法也是把问题一层一层地分解为规模逐渐减小的同类型的子问题。动态规划通常用来求最优化问题。此类问题可以有很多可行解,我们求出的是一个最优解,因为可能存在多个最优解。
分治法
子问题是相互独立的,若不独立,将重复计算
动态规划
可分为多个相关子问题,子问题的解被重复使用,子问题只求解一次,结果保存在表中,以后用到时直接存取
动态规划的条件
最优子结构
当一个问题的最优解包含了子问题的最优解时,称这个问题具有最优子结构
重叠子问题
在问题的求解过程中,很多子问题的解将被多次使用
步骤
1. 刻画一个最优解得结构特征
2. 递归地定义最优解的值
3. 计算最优解的值,通常采用自底向上的方法
4. 利用计算出的信息构造一个最优解
这里自底向上也可以改成自顶向下构造表法,即在递归地过程中计算子问题,若子问题的结果在表中出现则直接使用不用计算,否则计算后更新表。
问题一般采用动态规划法,当具有:
1)最优子结构性质时
2)高度重复性
若问题不是NP-hard问题
进一步分析后就有可能获得效率较高的算法。
若问题本身就是NP-hard问题
那么与其它的精确算法相比,动态规划法性能一般不算太坏
适用动态规划思想的算法:矩阵连乘、钢条切割、最长公共子序列、最优二叉搜索树、流水作业调度、0/1背包问题等。(尤其是背包问题,我到现在大部分还是有点不理解)
图论
咳咳咳,我也不想多说了。。。。。。这种东西简直是杀人不偿命,要你命三千有益身心健康。
定义
图由定点(vertex)的集V和边(edge)的集E组成。
每一条边就是一幅点对(v,w)。
如果点对是有序的,则图是有向的,又称为有向图。
图中的一条路径是一个顶点序列:w1,w2,w3…wN是的(wi,wi+1)属于E。
如果有一个顶点v到它自身的的边(v,v),那么(v,v)也被称为环。
如果一个无向图中从每个顶点到其他每个顶点都存在一条路径,则称无向图是连通的,又称为强连通的。如果一个有向图不 是强连通的,但是它的基础图图是联通的,那么有向图称为弱连通的。
完全图是其每一对顶点建都存在一条边的图。
拓扑排序
拓扑排序是对有向无环图顶点的一种排序,使得如果存在一条从vi到vj的路径,那么在排序中vj就出现在vi的后面。拓扑排序不是唯一的。
拓扑排序首先要找到一个入度为0的点,将其加入到队列中,标记为已删除;将该顶点的邻接点入度减1;再继续寻找入度为0的点,直至所有顶点遍历完成。要注意判断是否有环。时间复杂度:O(|E|+|V|)。
public void topSort() throws CycleFoundException {
Queue<Vertex> q = new LinkedList<Vertex>();
int counter = 0;
for (Vertex v : directedGraph.values()) {
if (v.inDegree == 0) {
q.offer(v);
}
}
while (!q.isEmpty()) {
Vertex v = q.poll();
v.topNum = ++counter;
if (v.adjEdges != null) {
for (Edge edge : v.adjEdges) {
edge.endVertex.inDegree--;
if (edge.endVertex.inDegree == 0) {
q.offer(edge.endVertex);
}
}
}
}
if (counter != directedGraph.size()) {
throw new CycleFoundException();
}
}
好了,以上就是我在福州差不多学到的东西了,但本人特别懒,不想复制粘贴太多的题目。总之,我现在只是触摸到了每一个算法的边缘,要深入研究的话还得多花点时间,虽然福州的老师讲课讲得十分简略详细,而且题目也非常的变态简单,但我还是经常连100分都拿不到,还有我对难度较高的东西还不是很理解,比如图论,哈希诸如此类,所以我得加把劲,努力跟上大部队。(顺便提一下,最后一天的图论题出的真是太恶心有良心了)