算法设计:

算法设计绪论

时间复杂度影响因素

问题规模n,输入序列I,算法本身A

时间复杂度排序

O(1)<O(logn)<O(n)<O(n²)<O(2n)<O(n!)<O(nn)

 

渐进复杂性

求算法渐进复杂性,使算法运行时间T(n)存在T'(n)满足limT(n)T(n)T(n)=0,则Tn为渐进复杂性。

结论

渐进复杂性&渐进上界&渐进下界&渐进精确:最高次项 上/下界:所有普通项升为最高次项/只保留最高次项

渐进记号O计算:常系数去掉,相加取最大,乘积找最大

分治-分而治之

分治主方法

主方法适用递归方程形式:T(n)=aT(nb)+f(n)

主方法的两个量

nlogba,f(n)

主方法题解口诀:谁大取谁,相等乘log n

分治基本思想

将一个规模为n的问题分解为k个规模为较小的子问题,这些子问题互相独立且与原问题相同。递归地求解这些子问题,然后利用子问题的解合并(构造)出原问题的解

分治算法与递归公式:T(n)=aT(nb)+f(n)

原问题规模n 子问题规模nb

分治算法步骤:分解 递归 合并

分治算法案例

前置内容:线性运算的复杂度为O(n)

大整数乘法

给定两个都是2k位的大整数A、B,求A与B的乘积

推广:用分治法求两个十进制都是n位的A与B的乘积

例:1024和2048分解成如下:

1024

10×10⁴/2+24

2048

20×10⁴/2+48

A B

10104/2+24

C D

20104/2+48

A×C+A×D+B×C+B×D

T(n)=4T(n2)+θ(n)

T(n)=θ(n2),T(n)=nlogba

二分查找

前提->线性表中的记录必须已按关键字值有序排列(一般情况下视为递增排列)

二分查找的方法:每次循环k都与R的中间元素的关键字(R[min].key)比较

在关键字有序序列(2,3,10,15,20,25,28,29,30,35,40)中采用二分查找法查找关键字为15的元素

第一次查找(0-10)-> 15<R[5].key ->下次去(low-4)查找 >high=mid-1;

第二次查找(0-4)-> 15>R[2].key ->下次去(3-high)查找 >low=mid+1;

第三次查找(3-4)-> 15== R[3].key ->查找成功,关键字比较次数为3

查找失败条件-> high< low

逻辑表达如下:

k==R[mid].key ->查找成功,返回当前元素的逻辑序号->return mid+1;

k < R[mid].key ->下次去(low至mid-1)递归查找k

k > R[mid].key ->下次去(mid+1至high)递归查找k

二叉树表达二分查找过程

0~4

6~10

0~1

3~4

1~1

4~4

6~7

9~10

7~7

10~10

25

10

30

2

15

3

20

28

35

29

40

二分查找最优θ(1) 最坏O(logn)

归并排序

举例:一个表中有8个元素,其关键字分别为(6,8,7,9,0,1,3,2)

说明采用二路归并排序方法进行排序的过程

6 8 7 9 0 1 3 2

6 8 7 9

0 1 3 2

6 8

7 9

6

8

7

9

0 1

3 2

0

1

3

2

T(n)=2T(n2)+θ(n),T(n)=nlogn

代码逻辑:

 

快速排序

开始时将序列首元素定位基准,通过快速排序将表一分为二,关键字小于基准值的放置在基准元素前,大于基准值的放置在基准元素后

6 8 7 9 0 1 3 2 4 5

5 4 2 3 0 1

9 7 8

1 4 2 3 0

5

8 7

9

0 1

2 3 4

7

8

2

3 4

3

4

0 1 2 3 4 5 6 7 8 9

时间复杂度的分析:

最坏O(n2)最好O(nlogn)平均O(nlogn)

循环赛日程表

循环赛日程表简述:设有n=2k个运动员要进行循环赛,现要设计一个满足以下要求的比赛日程表:

(1)每个选手必须与其它n1个选手各赛一次;(2)每个选手一天只能比赛一次;(3)循环赛一共需要进行n1天。

举例:有n=4个运动员要进行循环赛,现要设计一个满足以下要求的比赛日程表(1)每个选手必须与其它4-1个选手各赛一次:(2)每个选手一天只能比赛一次;(3)循环赛一共需要进行4-1天。

例子:分解前:1个4阶表格 分解后:4个2阶表格

推广:分解前:1个n阶表格 分解后:4个n2阶表格

对角线相同最后矩阵变为2个不相同的表,所以T(n)=2T(n2)+f(n)

时间复杂度:θ(n2)

部分快速排序--第k小元素

 

回溯法-回而溯之

深度优先遍历(DFS)

过程:从无向图中初始顶点v出发,先访问初始顶点v选择一个与顶点v相邻且没被访问过的顶点w,再从顶点w进行深度优先遍历,直到图中与顶点v邻接的所有顶点都被访问过为止

:O(n+e)

其中n为顶点个数,e为边数。

n皇后问题

 

 

广度优先遍历(BFS)

过程:访问初始点v,接着访问v的所有未被访问过的邻接点v1,v2,...vt

按照v1,v2,...vt的顺序访问每个顶点的所有未被访问过的邻接点

依次类推,直到图中所有和初始点v有路径相通的顶点都被访问过为止

image-20250609002442550

按照层级划分

 

 

贪心算法-贪心不足

贪心基本思想

从问题的某一个初始解出发,在每一个阶段都根据贪心策略来做出当前最优的决策,逐步逼近给定的目标,尽可能快地求得更好的解。当达到算法中的某一步不能再继续前进时,算法终止

贪心特点

每个阶段面临选择时,贪心算法都做出对当前来讲是最有利的选择。

算法简单,选择一旦做出不可更改,即不允许回溯

根据贪心策略来逐步构造问题的解

贪心算法效率高,但不稳定(不能求得最优解)

贪心四步

分解:将原问题分解为若干个相互独立的阶段

解决:对于每个阶段依据贪心策略进行贪心选择,求出局部最优解

合井:将各个阶段的解合并为原问题的一个可行解

证明:证明算法的正确性

贪心选择性质、最优子结构性质

贪心题解

背包问题

物品可以分割

:1Wniviwi使?

大的优先装入

 

 

会场安排问题

会场安排问题简述:设有n个活动的集合C={1,2..,n},1个资源(如会议室),而在同一时间内只能有一个活动使用该资源。活动i(i=1,2...,n)的开始时si;,结束时间fi,,且si<fi,。活动i占用会议室的时间段为半开区间[si,si)。如果[si,si)与[si,f;si)不相交,则称活动i与活动i是相容的。活动安排问题要求在所给的活动集合中选出最大的相容活动子集,也即尽可能地选择更多的活动来使用资源

用结束时间最早

O(n)使O(nlogn)

时间复杂度为O(nlogn)

Prim算法

 

Kruskal算法

总结

算法思想:

普里姆(Prim)算法->每次循环选择一个合适的顶点(稠密图)

克鲁斯卡尔(Kruskal)算法->每次循环选择一条合适的(稀疏图) 时间复杂度:

普里姆(Prim)算法 每次循环需要在所有的U中顶点和V-U中顶点的边选取权值最小的边

时间复杂度 ->O(n2)->只与顶点数n有关

克鲁斯卡尔(Kruskal)算法 每次循环需要在剩余的边中选取权值最小的边

时间复杂度 ->O(eloge)->只与边数e有关 适用范围 普里姆(Prim)算法 ->稠密图

克鲁斯卡尔(Kruskal)算法 ->稀疏图

Dijkstra算法

 

 

动态规划

动态规划的特点

常用情况

主要用于求解以时间划分阶段的动态过程的优化问题,动态规划算法通常用于求解具有某种最优性质的问题

基本思想

经分解得到的各个子问题往往不是相互独立

在求解过程中,将已解决的子问题的最优值进行保存,在需要时可以轻松取出

Dynamic Programming

  1. 确定dp数组(dp table)以及下标的含义

  2. 确定递推公式

  3. dp数组如何初始化

  4. 确定遍历顺序

  5. 举例推导dp数组

递推公式很多时候决定了dp数组如何初始化

遍历对dp递推公式进行

动态规划题解

矩阵连乘

A1,A2矩阵相乘次数 = A1的行数×A1的列数×A2的列数

= A1的行数×A2的行数×A2的列数

两个矩阵相乘取第一矩阵的行第二矩阵的列

如:A1(57),A2(710),A3(103)

 

A1|A2A3=>A2A3=7103=210>(73)A1=(73)(57)=147total:357

A1A2|A3=>A1A2=5710=350>(510)A3=(510)(103)=150total:500

最优解为357次

 

最长公共子序列

方法:

1.比较字符异同 异:看左看上取最大;同:看左上角+1重复直到表格填完

2.比较字符异同 比较xy字符(异:看左/上数字大小|同:先保存走左上);谁大往谁走,相同一起走;直到边缘