ACM算法思想总结

能解释一下单调栈吗?{
单调栈就是维护栈内元素保持单调性,单调递增或单调递减。
比如给一个数组,大小为5,元素分别是 1 3 2 5 4 我要维护单调递增的栈,
此时栈内元素为空,从数组开头扫描,最开始是1,因为栈空,所以直接加入到栈内,
接下来是3,3比栈顶元素1要大,保持单调递增,加到栈内,接下来是2,比栈顶元素
3 要小,弹出3,栈顶元素为1,2比1大,此时可加入到栈顶。可以知道2往左边最远
可扩展到1这个位置,不包括1,即1之后的元素到2之前都大于等于2。后面来了5, 5
比2大,加到栈内,最后是4, 4 比5小,弹出5, 4 比2大。所以能够知道2之后的元素
到4之间都大于或等于4。
}
能解释一下单调队列吗?{
单调队列就是维护队列里元素的单调性,单调递增或者单调递减。
比如给一个数组,大小为5,元素分别是 4 1 2 3 5, 我现在给一个滑动窗口,大小
为3,滑动窗口从数组开头开始滑动,每次滑动找出窗口中的最大值。比如刚开始是
4 1 2 ,最大值为4 ,接下来是1 2 3, 最大值是3 ,接下来是2 3 5, 最大值是5.
如果每次滑动一次,就循环去找窗口中的最大值,复杂度是O(n*m), 效率过低,那么用
单调队列可以实现O(n)的实现。
设置一个队列,开始时为空,把4加入队列,然后到1,加入到队列中,因为1可能是以1
为开头的窗口元素。
继续是2, 2 比1小,弹出1,说明1不可能成为任何一个窗口的最大值,2加入到队列。
前3个元素已经访问完,最大值为单调队列的队首元素4。接下来到3,
3 比2大,弹出2,比4小,加到队尾。因为4距离3的大小已经超过了窗口大小,则需要
从队首移除。此时队首变成了3,即此时窗口最大值为3,对应1 2 3 这个窗口。最后是
5, 照此规则进行。
}
解释一下字典树?{
字典树可用于对多个字符串建立一棵树,每个节点对应一个字符,树的某些路径可共用。
比如给4个字符串:abc abb acb acd 字符串abc建立了一条路径,每个节点对应的字符
是a b c, 到abb时,ab得到了共用,需要在后面建立一个c字符的节点。再是acc, a
得到了共用,需要在其后建立一个c字符的节点,再建一个b字符的节点。不过abb和acb
并不能共用a和最后一个b字符对应的节点,只能共用相同的前缀。最后是acd,照此原则。
建立好一棵字典树之后。就可以查询某个字符串是否在字典树中。
字典树的应用: 串的快速检索,对串排序,查询串的公共前缀。
优点: 节省空间。查询速度快。
拓展{
可持久化字典树
假如给一个数组,大小为10,然后把数按照比特位插入到可持久化字典树中,
假如所有的数不超过10000,最高位从第16位开始,从高位往低位开始建成一条
路径。每个节点只有0或1 。第2个数会利用第一个数的节点的相关信息。第3个数会利用
前面构建的字典树的信息。直到所有树插入进去。如果要查询某个数是否在第3到第8个数
有出现,则第1 , 2 个数不能包含在内。如果只是普通的字典树,那么不可能实现这种
区间的查询。
}
}
二分图解释一下原理?{
举个例子,我有5件上衣,6条裤子,有一些限制条件,假如把上衣编号为a,b,c,d,e
裤子编号为 1,2,3,4,5,6 限制条件比如a可以和1,3,5 搭配,不能和其他裤子搭配。
b也只能其中某些裤子搭配。每件上衣和裤子只能使用一次,那么最多可以得到多少
套装。这就是一个二分图匹配问题。假如现在a和1搭配了,当搜c的时候,发现c可以和
1 搭配,1保存的匹配对象是a,a也可以和2搭配,且2现在没有匹配对象,那么可以取消
a和1这条边,将a和2连一条边,c和1连一条边,这样匹配数就增大了。直到不能再增加
匹配数为止。
}
极大团{
团里的每个节点都与其他节点有相连,即这个团有 N*(N-1)/2 条边。
}
迪杰斯特拉算法{
迪杰斯特拉算法是一种最短路算法,可以求其他节点到某一节点的最短路。
假如有5个点,1是起始节点,然后去找距离1最近的节点添加进来,比如是3,接着在
2,4,5 中找距离集合最短距离的点,即2到1 3, 4 到1 3 ,5到1 3 中最短的距离。再
将其添加进来。直到找完所有的点。 添加进一个点时,就更新所有到这个集合未添加的点
的最小值与这个点的距离的较小值。
朴素的复杂度是O(n^2),如果用优先队列优化的话,可以达到O(nlg(n))。
}
spfa(最短路径快速算法){
也是一种最短路算法。利用到队列。
假如有5个点,1是起始节点,设置数组D[], D[i]代表点i到1的最短距离,开始时置非
常大的值。先将1加入到队列,然后开始从队列取出队首元素,此时是1,找到与1相连
的点,比如是2和3, 更新D[2],D[3]的最小值,将2,3 加入队列。再取队首元素。此时
是2,假如3,4,5 与2相连,更新D[3],D[4],D[5]的最小值,可能会出现D[3]比之前要小。
因为3在之前已经加入了队列,则此时不需要再将其加入队列。直到所有节点的D值不发生
变化或队列未空时就结束算法。
朴素的复杂度为(VE)。但稳定性不佳。用优先队列优化可达O(nlg(n))
适用于稀疏图,不适于稠密图。
}
弗洛伊德算法{
一般三层循环,复杂较高,约为O(n^3),但是它可以求出每两个点之间的最短距离。
比如要求D[i][j]的最短距离,可以用一个中间节点k,利用D[i][k]+D[k][j]来更新。
所以三层循环分别对应i,j,k。
}
强连通算法{
强连通算法可以找到强联通分量,每个分量相当于一些点的集合。这个集合的每两个
点可以互达。比如有一个有向环,1->2->3->1 则1 2 3是一个连通分量, 因为他们都
可以互达。设置两个量 dfn 和 low, dfn代表这个节点第一次被访问时的顺序编号,
low代表从这个节点一直搜下去可以搜到的最小节点的编号。如果low比dfn小,说明
它搜到了之前已经访问过的节点,形成了环。于是他就属于某一个分量。
}
双连通算法{
跟强连通差不多。
}
网络流算法{
考虑一个模型,有n个点m条边的图,每条边设置了最大容量和流量。有一个源点和汇点。
比如有5个点,1是源点,5是汇点。每次从1开始找一条可到达5的路径,路径要保证能
有流量传输。然后加上流量后,修改这条路上的边的流量值。一直循环下去,直到5
不能增加流量。
}
Prim算法{
Prim算法是实现最小生成树。
假设有5个点的图。最开始选择1作为起点。现在去找2,3,4,5 中到1的最短边,加上这条边
的长度,并把选中的点加进集合。比如选择了3,接下来再找2,4,5 中距离集合最短的距离。
再将选中的点加进来。直到所有的点加进集合。
复杂度为O(n^2) 适合稠密图。
}
克鲁斯卡尔算法{
也是实现最小生成树的算法。
将所有的边进行排序。对于某条边,两个点设为a,b,用并查集查找到a和b所属树的根节点。
如果两者的根节点相同的话,说明a,b在同一棵树里,加进这条边会形成环。没必要。
如果两者的根节点不同,说明a,b在不同的树里,可以加入a->b这条边。将两颗树合并。
直到所有的节点加进来。
复杂度为O(E*lg(E)) 适合稀疏图。
}
后缀数组怎么实现?{
以字符串 abcab为例,刚开始以一个字符来排序,abcab对应的大小分别为 1 2 3 1 2,
再在第一次的基础上比较的字符串倍增,按照两个连续的字符比较,第一个a和第二个a
之前的排名大小都是1,发现他们后一个字符都b, 两者的排名还是置为1,
第一个b和第二个b之前的排名是2,现在发现第二个b后面没有字符,则第二个b的排名
在第一个b之前。一个设为2,一个设为3,剩余的比较也是如此。那么现在的排名
分别是1 3 4 1 2, 再比较四个字符。直到所有的排名已区分开。
采用倍增的方式,所以复杂度是O(nlg(n))
}
ac自动机怎么实现?{
ac自动是在字典树上进行字符串匹配。如果要进行匹配的话,可以先了解一下KMP算法
(略过),假如有两个字符串aa baaa插入到字典树中。第一个字串的a的失配指针指向
根,第二个字符串的失配指针指向根(画图会比较好解释。。。)
}

 

 

猜你喜欢

转载自blog.csdn.net/weixin_38654235/article/details/88739070