算法分析与设计笔记(一)

复杂度分析

  • 低阶函数

  • 同阶函数

  • 高阶函数

  • 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去掉最后一位的每个字符计算偏移表,其他字符直接移动整个字符串长度
  • 算法描述

原文地址:https://www.cnblogs.com/ranjiewen/p/6986332.html