《序列和字符串》由会员分享,可在线阅读,更多相关《序列和字符串(105页珍藏版)》请在金锄头文库上搜索。
1、2005年浙江省队培训第3讲 序列和字符串的算法1目录一、算法分析基础二、排序三、序列的算法四、串的算法2一、算法分析基础一、算法分析基础3抽象操作抽象操作(abstract operations). 对于单一操作(如加法)的算法, 运行时间 = 操作时间 * 操作次数 (不考虑cache等体系结构方面的影响)操作时间取决于计算机操作次数取决于算法算法分析: 只考虑算法特性, 因此只考虑操作次数4操作数函数在很多情况下, 基本操作数可以写成N的函数f(N), 其中N代表主要参数例如, 给N个数排序的问题, N就是主要参数, 它最明显的决定了问题的复杂程度, 也影响着算法效率存在多个主参数的情况
2、类似定义, 本节暂不考虑5比较两个算法假设有两个算法算法一执行了f(n)=n2次基本操作算法二执行了g(n)=n2/2次基本操作那个算法好呢?绝对操作数算法二好,因为g(n) f(n)增长情况呢?n扩大10倍,f(n)扩大100倍,g(n)也扩大100倍两个算法的增长情况一样!我们说: 渐进时间复杂度一样!6渐进时间复杂度f(n)=n2和g(n)=n2/2结论: 增长情况一样问题: 如何表示“增长情况”?方法: 把f(n)和g(n)变成“渐进”形式,然后直接比较如何变成“渐进”形式?只保留最“大”项, 忽略系数, 符合前面介绍的原则例1:3n4+8n2+n+2 n4例2:2n+1+n100+5
3、 2n (为什么n+1变成了n?)7常见的函数增长f(N)的渐进形式往往是以下某个函数1(常数, constant): 和N无关, N多大运行时间都一样logN(对数, logarithmic): 这是个增长缓慢的函数. 若底为2, 则log1000000约为20N(线性, linear): 对于必须处理N个输入数据, 或者得到N个输出数据的问题, 算法(在渐进意义下)是最优的.N2(平方, quadratic): 若N加倍, 函数值变为四倍2N(指数级, exponential): N很小时2N已经很大了多项式算法Na: 有效算法8函数增长和运行时间9对数函数若bL=n, 记L = logb
4、n,称L为以b为底的n的对数对数的公式logan + logam = loganmklogan = logank换底公式: logan/logbn=logba对数是一种增长很慢的函数log21000 约为 10log21000000 约为2010对数函数由于算法分析忽略常数,通常logN不指定底, 默认情况为2, 记为lgN, 若底为自然对数e(=2.71828), 记为lnNlgN为N二进制表示中的位数,lg10=3.322有时也取对数的对数 loglogN. 由于lglg1012=lg39.865.32, 所以一般可以把它看作常数11其他常见函数和近似12复杂度分析不清楚怎么办只分析上限,
5、而不需要精确计算实际运行时间若n充分大时|f(n)|=c|g(n)|,其中c为某常数记f(n) = O(g(n),表示g(n)为f(n)的渐进上限例1:5n2+3n+1 = O(n2)例2:2n3 = O(7n8)类似的,可以定义下限如果上下限相等,增长情况完全一样,记做由于上限有无限多个,我们希望它尽量精确, 否则我们的分析就过于悲观了,实际算法没那么糟糕13递归式在很多时候, 无法写出时间复杂度T(n)的显式表达式, 而只能得到递归方程公式一: T(1)=1, T(n)=T(n-1)+n, 则T(n)为n(n+1)/2公式二: T(1)=1, T(n)=T(n/2)+1, 则T(n)约为l
6、gN公式三: T(1)=0, T(n)=T(n/2)+n, 则T(n)约为2n公式四: T(1)=0, T(n)=2T(n/2)+n, 则T(n)约为nlgN公式五: T(1)=1, T(n)=2T(n/2)+1, 则T(n)约为2n考虑一般情形: T(n) = aT(n/b) + f(n)14递归树分析T(n) = aT(n/b) + f(n), a, b为常数,f(n)为给定函数递归树: T(n) = f(n)+af(n/b)+a2f(n/b2)+aLf(n/bL)其中最后一项为递归边界,即n/bL=1,因此L=logbn15公式四分析T(n) = aT(n/b) + f(n)递归树得到的
7、结果:T(n) = f(n)+af(n/b)+a2f(n/b2)+aLf(n/bL)其中L=logbn公式四:T(n) = 2T(n/2) + na = 2, b = 2, f(n) = n对于第k项,有2kf(n/2k) = 2k *n/2k = n一共有log2n项T(n) = n * log2n = O(nlogn)16最大连续序列问题给一串整数a1n,求出它和最大的子序列,即找出1=i=j max then max := sum; end;思想:枚举所有的i和j,计算ai+aj,选择最大的时间复杂度如何分析?三层循环内层操作次数取决于i, j中层操作次数取决于i18算法一分析当i和j一
8、定的时候,内层循环执行j-i+1次总次数为应该如何计算?方法一:直接计算先计算里层求和号,得再加起来?好复杂直接算法需要利用公式12+n2=O(n3)一般地,有1k+nk=O(nk+1). 证明: 数学归纳法19算法一分析(续)总次数为:完全的计算太麻烦能不能不动笔就知道渐进时间复杂度呢?何必非要计算出详细的公式再化简呢?里层求和计算出的结果是O(n-i)2)12+22+n2=O(n3)每步都化简!但是要保留外层需要的变量结论:算法一时间复杂度为O(n3)经验:一般只能支持 n max then max := sj si-1;时间复杂度:预处理+主程序=O(n+n2)=O(n2). n=500
9、022算法三用一种完全不同的思路最大子序列的位置有三种可能完全处于序列的左半,即j=n/2跨越序列中间,即in/2j用递归的思路解决!设max(i, j)为序列aij的最大子序列, 那么23算法三(续)用递归的思路解决!设max(i, j)为序列aij的最大子序列设mid = (i + j)/2,即区间aij的中点最大的第一种序列为max(i, mid)最大的第二种序列为max(mid+1, j)问题:最大的第三种序列为?既然跨越中点,把序列aij划分为两部分aimid:最大序列用扫描法在n/2时间内找到一共只有mid-1=n/2种可能的序列,一一比较即可amid+1j:同理一共花费时间为j-
10、i+124算法三分析如何分析时间复杂度呢?我们没有直接得到具体的T(n)的式子但是容易得到递推关系T(n) = 2T(n/2) + n设时间复杂度的精确式子是T(n)第一、二种序列的计算时间是T(n/2),因为序列长度缩小了一半第三种序列的计算时间是n由递归式四, 得T(n)=O(nlogn)25算法四算法二的实质是求出i=j,让sj-si-1最大对于给定的j,能否直接找到在j之前的最小s值呢?从小到大扫描jj=1时,只有一个合法的i,即i=1, s1-1=0如果sj变大,则最小的s值和上次一样如果sj再创新低,应该让sj作为今后的最优s值min_s := 0;For j :=1 to n d
11、o begin if sj max then max := sj min_s;end;时间复杂度很明显:O(n). n = 1,000,00026总结算法时间复杂度规模分析方法枚举O(n3)约200分层求和优化枚举 O(n2)约3000明显分治O(nlogn)约105递归树扫描O(n)约106明显27二、排序二、排序28问题1: 排序给n个数, 从小到大排序29思考: 篮球俱乐部给定N个人的身高(1.95m2.05m),要求将他们排成一列,使得任意选取两个人,他们中间如果存在K个人,并且身高和为S,那么S与K2m的差的绝对值小于等于0.1m。 30插入排序和选择排序增量算法 选择排序?取决于未
12、来的输入? 插入排序:来一个插一个部分排序 插入排序?如果前k大的是最后k个元素 选择排序:选的前k个就是前k大元素结论:排序算法的选择要看实际应用31归并排序二路归并1, 2, 4, 7, 93, 5, 6, 10, 11合并:n分治sort(i, j),设时间为T(n) 排前一半:sort(i, mid), 时间T(n/2) 排后一半:sort(mid+1, j),时间T(n/2) 合并起来:n32归并排序算法分析时间: T(n) = 2T(n/2) + n T(n) = O(nlogn)空间: S(n) = 2S(n/2) + n? 空间可重用!最好、最坏、平均是一致的33例题: 煎饼目
13、标:从小到大排序从下数第k个开始往上翻(a) (b) (c) 3 1 34问题2: 逆序对数目逆序对数目:i aj枚举:O(n2). n = 5000利用归并排序的框架 j = mid,递归处理i mid j,合并的时候顺便求! 1, 2, 4, 7, 9 3, 5, 6, 10, 11取后一半元素时,前一半还剩多少个就是时间复杂度:O(nlogn)35快速排序找一个数x 让x左边的数都比x小 让x右边的数都比x大 分别给两边排序 核心:如何调整x左右的数?从两边往中间扫描 在x左边第一个比x大的地方停下来 在x右边第一个比x小的地方停下来两个交换,正好都满足要求36快速排序例子:1, 8,
14、2, 9, 6, 4, 7, 3, 5第一次交换8和5:1, 5, 2, 9, 6, 4, 7, 3, 8第二次交换9和3:1, 5, 2, 3, 6, 4, 7, 9, 8 第三次交换6和4:1, 5, 2, 3, 4, 6, 7, 9, 8两个指针汇合,完成时间复杂度:O(n)37快速排序分析最好情况:均分成两半,则是O(nlogn)最坏情况:分成长度为1和n-1,则是O(n2)这是不是说明快速排序比归并排序差显然不是,否则就不会叫“快速排序”了嘛加入随机数, 几乎可以保证是O(nlogn), 系数比归并排序小随机数让坏情况从数据转移到了随机运气38快速排序一些小细节n = 10时用插入排
15、序加速x如何选?中间?随机(随机数产生开销)?警告!快速排序不稳定!原因?如何修改?最坏情况:数据随机数39问题3: 求序列中第k大数方法一: 先排序O(nlogn)方法二: 借用快速排序的框架只需要根据k的大小只处理一边平均情况:O(n)40例题: 士兵排队问题n=10,000个士兵在网格中位置用(x, y)表示 士兵可以沿四个方向移动 进入某一行且排在一起 假设格子可以容纳所有士兵41分析行:感觉在”中间”中位数 or 平均数?假设往下一行列?(请思考)42思考: 加权中位数X轴上有n个点,第i个点都的权值为正数Vi,要求在X轴上找出一点P,使sumVi*|xp-xi|最小43计数排序特殊
16、的排序对象:0100的整数(如分数)开一个count0.100的数组,记录个数 for i:=1 to n do inc(countscorei);时间复杂度为O(n), 比快速排序还快关键: 利用了关键码的范围44基于比较的排序时间下限简单起见,不考虑相等的情形可以获得多少信息? 一次比较,两种结果 k次比较2k种结果需要获得多少信息? n个数的排列有n!种 最后只剩一种可能性时,排序完成45基于比较的排序时间下限需要比较多少次? 比较k次以后最好只能保证剩n!/2k种可能性 n!/2k=1时,即k=log(n!)时排序完成log(n!) = (nlogn)46三、序列的算法三、序列的算法4
17、7问题1: RMQ问题给n个数a1n设计在线算法, 对于每个询问(L, R), 回答aLR内的最小值48分析算法一: O(n2)-O(1)RMQi,j = minRMQi,j-1, Aj用长度递增的顺序计算所有RMQi,j算法二: O(n)-O(n1/2)分为长度L=n1/2的小块, 共L块预处理得到每个块的最小值询问最多涉及L个块和头尾块的2L个元素好处好处: 修改也是修改也是O(n1/2)的的49分析算法三: O(nlogn)-O(1)di,j为从i开始的, 长度为2j的范围内的RMQ递推式di,j=mindi,j-1,di+2j-1,j-1. 预处理是O(nlogn)的询问时取k=log
18、2(j-i+1), A为从i开始长度为2k的块, B为以j结束的长度为2k的块, 则A和B覆盖区间(i,j). 询问是O(1)的算法四: O(n)-O(1)用Cartesian-Tree转化成LCA问题50问题2: k路归并问题把有k个有序表, 合并成一个有序表.元素共有n个.51分析每个表的元素都是从左到右移入新表把每个表的当前元素放入堆中, 每次删除最小值并放入新表中, 然后加入此序列的下一个元素每次操作需要logk时间, 因此总共需要nlogk的时间52问题3: 序列和的前n小元素给出两个长度为n的有序表A和B, 在A和B中各任取一个, 可以得到n2个和. 求这些和最小的n个53分析可以
19、把这些和看成n个有序表:A1+B1 = A1+B2 = A1+B3 =A2+B1 = A2+B2 = A2+B3 =An+B1 = An+B2 = An+B3 =类似刚才的算法, 每次O(logn), 共取n次最小元素,共O(nlogn)54问题4: 多个有序表的第k大元素有m个有序表, 每个表里有n个元素.所有元素不超过W设计在线算法, 回答这m*n个元素中第k个元素的值55分析二分元素大小x计算每个有序表里比x小的元素个数k, 每个表O(logn), 共O(mlogn)如果k=k, 输出x如果kk, 把x变小总时间复杂度O(mlogn*logW)56问题5: 范围内第k大数给n个数A1n设
20、计在线算法, 对于询问(i, j, k), 返回Ai.j第k大元素57分析预处理:建立线段树,每个线段保存该区间内元素排序好的序列查询处理:任意i,j可分解为最多2logn个不重叠区间的并,只需二分W, 每次计算2logn个区间内一共有多少个数比W大,用logW次时间可求出第k大元素58分析区间内的数已排序,用二分每个区间求比W大的数logn累加所有2logn个区间比W大的数,共log2n实现: 一个归并排序可以同时构造线段树和每个节点内的排序数组. 时间: O(logW*log2n)空间:O(nlogn)59例题: 区间有n个闭区间ai,bi,其中i=1,2,n,每一段被涂成黑色整个数轴被涂
21、为几段黑色?60分析按左端点从左到右排序从左到右扫描,若下一个区间的左端点分离,则区间数加一,否则扩展当前区间的右端点时间复杂度:O(nlogn)61例题: 轮廓线每一个建筑物用一个三元组表示(L, H, R), 表示左边界, 高度和右边界轮廓线用X, Y, X, Y这样的交替式表示右图的轮廓线为: (1, 11, 3, 13, 9, 0, 12, 7, 16, 3, 19, 18, 22, 3, 23, 13, 29, 0) 给N个建筑,求轮廓线62分析算法一: 用数组记录每一个元线段的高度离散化, 有n个元线段每次插入可能影响n个元线段, O(n), 共O(n2)从左到右扫描元线段高度,
22、得轮廓线算法二:每个建筑的左右边界为事件点把事件点排序, 从左到右扫描维护建筑物集合, 事件点为线段的插入删除需要求最高建筑物, 用堆, 共O(nlogn)63思考: 照亮的山景在一片山的上空,高度为T处有N个处于不同水平位置的灯泡,如果山的边界上某一点与某灯i的连线不经过山上的其他点,我们称灯i可以照亮该点。开尽量少的灯,使得整个山景都被照亮。灯的位置固定。一定有解 64思考: 喷水装置有一块草坪,长为l,宽为w在它的中心线上装有n个点状的喷水装置效果是让以它为中心半径为ri的圆被润湿选择尽量少的喷水装置把整个草坪全部润湿,65例题: 啤酒厂n个点连成环状,每相邻两点间有距离值如果选择其中一
23、个点建立啤酒厂,则它需要给所有其他城市运送啤酒每个城市都有啤酒需求量di运到城市i的费用为啤酒厂到i的最小距离乘以di选择让总费用最小的啤酒厂66分析如果啤酒厂建在s,则所有城市分为两部分s顺时针方向移动时p也顺时针方向移动,处理p移动的时间为O(n)总费用的改变量来源于四部分:始终S-的部分,始终为S+的部分,从S-变为S+的部分,从S+变为S-的部分67例题: 水库已知有N个水库,水库的当前水量为Wi,能够储存的容量为Li。现在可以选择炸掉其中的某些水库:一旦炸掉第i个水库,那么水库中的水就会流到第i+1个水库。如果某个水库的当前水量超过了容量,那么这个水库将回倒塌,而所有当前的水也会流到
24、下一个水库。炸第i个水库需要的费用为Ci,现在的目标是使第N个水库倒塌或者爆炸。68分析设用炸弹炸的第一个水库为第i个水库。则显然第1i-1个水库都安然无恙,第i+1n个水库要不被炸掉要不被水冲倒塌。(否则费用不会最小)第j个水库是否要需要炸掉?这只要看Wi+Wj是否大于Lj即可:设Si=W1+Wi,则Sj-LjSi-1时不需要用炸弹,否则需要用炸弹。69分析若我们从大到小的枚举i,则Si-1是递减的,也就是说当i=k水库j不需要用炸弹时,iSi-1的水库的从堆中删去。 70例题: 序列反转N个球按照编号从1到N排放在桌上。定义一种操作,每次将xy范围内的球,进行倒置,就是把它们反过来放。如2
25、 3 7 4变成了4 7 3 2。给定M个连续的操作,要求我们给出操作后的序列。71算法一离散化加模拟。初始时候,只有1.N一个块,每次处理一个操作,会将一个块分成最多三块,块的顺序适当改变,另外每个块自身可能被翻转因为我们基于“块”进行操作,类似于离散化,每次最多增加2块,因此总时间复杂度为O(M2)。 72算法二首先把这n个数分成sqrt(n)段, 每段长度基本相等. 处理时只要处理首尾两段就可以了, 中间的段只要记录当前是顺序还是逆序时间复杂度O(n0.5m)73四、串的算法四、串的算法74字符串字符串: 可变长的字符数组. 本文中串S的第i个字符用Si表示, 从第i个到第j个字符用Si
26、.j表示实现: 可以在末尾加一个结束标志, 如0, 也可以记录字符串的长度基本操作: 取长度, 取指定位置的字符, 取子串, 模式匹配75问题1: 替换连续空格问题: 把连续空格改为单个空格. 例如对输入s=There are many spaces., 输出为There are many spaces.76分析算法一: 每遇到空格就把后面的字符往前移算法二: 用两个指针, 读指针持续移动, 当遇到第二个空格时写指针不动.比较: 算法一最坏O(N2)的, 算法二是O(N)的启发启发: 字符串问题一般容易设计正确的算法字符串问题一般容易设计正确的算法, 但需要深入分析才能找到高效算法但需要深入分
27、析才能找到高效算法77问题2: 字符串排序给n个字符串把它们按字典序字典序从小到大排序78分析和数值排序类似, 基本操作是字符串比较由于字符串可能比较长,一般不移动字符串本身, 只修改指针79问题3: 模式匹配给定串T,寻找串P是否在T中出现T称为母串,P称为模板。一般记T和P的长度分别为n和m输入T和P,Ti为T从第i个字符开始的后缀输出判定问题:P是否在T中出现完整匹配:P出现的位置集合前缀匹配:对于1=iyMra则只有可能是2431. 但如果是abab-aabb, 有可能是1324, 1342等. 但如果又有cdcd-ddcc, 则无解了. 排列的第i个数的取值集合为所有集合的交知道了第
28、i个位置可以取哪些数, 求匹配图是特殊的!99例题: 关键词给出一个长度为n的01串A,求一个最短的由01串B,使B不是A的子串。100分析m=logn取上整,由抽屉原理知B长度=m可以把长度不超过m的子串一一对应于一棵深度为m的完全二叉树T的节点。根节点编号为1对应空串S1,i的左儿子编号为2i,对应Si+0,i的右儿子编号为2i+1,对应Si+1用Marki表示节点i对应的子串是否在串A中出现过。我们的任务是求最小的i使得Marki=false。101分析用O(n)的方法可以把T的叶子结点的Marki都计算出来(每次左移一位并加新值)把An-m+1,n,An-m+2,nAn,n所对应的值也
29、标记为true(每次右移一位)从大到小的循环i如果Marki=false则更新最小值为I否则Marki shr 1=true102例题: 重复有一个n个长度不超过L的单词,单词中的字母来自字母表a,.,z 。编程求所有单词中最长的公共子串(必须在原串中连续) 103分析枚举最短串子串再用KMP:O(nL3)枚举所求串在最短子串中的开始位置,取其他串KMP结果(最远能匹配到的位置)的最小值为结束位置,O(nL2)或者枚举开始i和结束j,但成功时j+,不成功时i+104思考: 窗口属性对于所有K,每连续K个字符组成的串最多有K+1种, 如:011010给一个串, 求最小的s, 使得前s个字符有WP, 前s+1个没有105