- 算法设计与分析之入门篇
- 跟着视频学习,感觉这里面的主要算法很重要!
- 对很多经典的问题理解不够。
复杂度分析
低阶函数
同阶函数
高阶函数
master定理求解阶数/迭代法求解具体的
递归方程
- 整数划分问题
将正整数n表示成一系列正整数之和,n=n1+n2+n3+......nk(其中,n1>=n2>=......nk>=1,k>=1),正整数n的这种表示称为正整数n的划分。正整数n的不同划分个数称为正整数n的划分数,记作p(n)。例如:正整数6有11总不同的划分
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1;
记q(n,m)为正整数n的所有不同划分中,最大加数n1不大于m的划分个数。可以建立如下递推关系:
前面三个递推式比较好理解,关键是第四个递推式。当n>m>1时,n的划分由两部分组成。以整数q(6,3)为例,q(n,m-1)内容是第5排和第6排内容,不大于2的6的划分;q(n-m,m)内容是第4排,不大于3的(6-3=3)的划分。
//2-4 整数划分问题
#include "stdafx.h"
#include <iostream>
using namespace std;
int q(int n,int m);
int main(){
cout<<q(6,6)<<endl;
return 0;
}
int q(int n,int m)
{
if( n<1 || m<1)
{
return 0;
}
else if(n==1 || m==1)
{
return 1;
}
else if(n<m)
{
return q(n,n);
}
else if(n==m)
{
return q(n,m-1) + 1;
}
else
{
return q(n,m-1) + q(n-m,m);
}
}
- 汉诺塔问题
- 古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个和尚想把这64个盘子从A座移到B座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,小盘在上。在移动过程中可以利用B座,要求输出移动的步骤。
#include <iostream>
using namespace std;
void hanoi(int n, char a, char b, char c);
int main(){
char a = 'A', b = 'B', c = 'C';
hanoi(3, a, b, c);
return 0;
}
//借助c,将n个盘子从a移到b
void hanoi(int n, char a, char b, char c)
{
if (n > 0) //n等于1直接输出
{
hanoi(n - 1, a, c, b);//借助b,将n-1个盘子从a移到c
cout << "将" << a << "中最大的盘子从" << a << "移到" << b << endl;
hanoi(n - 1, c, b, a);//借助a,将n-1个盘子从c移到b
}
}
分治法
- 设计过程分三阶段:划分,求解,合并
- 自顶向下
- 大整数(二进制)乘法
- 最大值最小值问题(类似归并算法)
- 中位数问题
- 从n个不同的数中选第i大的元素(线性时间)
- 快速傅里叶变换
动态规划
- 子问题相互独立,若不是相互独立,分治方法将重复计算公共子问题,效率低
- 自底向上
- 一类优化问题
- 使用动态规划的条件:优化子结构,重叠子问题
- 矩阵的乘法
0-1背包问题
动态规划方法可用的条件
- 优化子结构
- 子问题重叠性
- 子问题空间小
贪心法
- 求解最优化问题
- 每一步都有一组选择,作出在当前看来最好的选择
- 希望通过作出局部优化选择达到全局优化选择
- 贪心算法不一定总产生优化解
- 贪心算法是否产生优化解,需要严格证明
贪心算法产生优化解的条件是:
- 贪心选择性
- 优化子结构(严格)- 任务安排问题
哈夫曼编码问题(前缀码-最优二叉树)
搜索策略
- 暴力美学
- 转换为树搜索问题
- 深度优先和广度优先
- 广度优先-队列实现
- 深度优先-栈实现
- 搜索的优化
- 爬山法(使用贪心方法确定搜索的方向)-局部优化
- Best-First搜索策略-全局优化-用堆实现
- 分支界限(可以有效地求解组合优化问题)(剪枝)-缩小解空间,加速搜索
- 八数码难题(8 puzzle)(广度优先)
- 求解子集和问题(深度优先)
- 哈密顿(Hamiltonian)环问题(深度优先)
字符串搜索
- 字符串匹配问题
- 计算匹配算法的复杂度
O(m*(n-m))
- 计算匹配算法的复杂度
Rabin-Karp
算法,指纹思路。如果两个字符串hash后的值不相同,则它们肯定不相同;如果它们hash后的值相同,它们不一定相同。- RK算法的基本思想就是:将模式串P的hash值跟主串S中的每一个长度为|P|的子串的hash值比较。如果不同,则它们肯定不相等;如果相同,则再诸位比较之。
- 参考:串的模式匹配算法---RK,Rabin-Karp指纹字符串查找算法
- 补充Horner算法
KMP算法
- 利用已有部分匹配中的信息
- 需要寻找overlap
基于自动机的算法;
- 前缀表,由于sigma有可能比较大,所欲忘记未匹配的字符(alfa)
- 这样可能导致再次匹配失败,但是也只是多匹配了一次,这样换取了时间和空间的优化
- P的前缀和P的前q位的后缀求最大的overlap,q+1位匹配失败
核心就是求前缀表
- KMP算法流程
BMH算法
- 用逆向简单算法中增加了启发式规则
- P从前往后走,但模式P匹配时从后往前匹配
- 真实应用中,不匹配的概率大,最坏也可能是O(n*m)
- 对P去掉最后一位的每个字符计算偏移表,其他字符直接移动整个字符串长度
- 算法描述