做了好些题了,作个简单小结,以作回顾保存:
数据结构
一个数据结构最基本的操作有增删改查等,当然还有各种有附加条件的操作,我们选择
基本数据结构一般来说是平摊分析的结果,即一个高性能操作的子集,忽略很少量的高复杂度的操作,这样从平均角度来看时间复杂度还是低的。但在设计数据结构时我们往往要注重数据结构各操作之间时间复杂度的平衡性,比如一个操作的时间复杂度为O(1),另一个操作的时间度杂度是O(n),在不能保证O(n)是很少量操作的情况下,如果可以,我们更希望的是两种处于中间的时间复杂度,比如O(lg(n)),这样一个操作系列的时间复杂度便为O(lg(n))。我称它为平衡设计。
基本数据结构:
栈:经常用递归栈来代替,用于DFS
队列:一般用于BFS
线性链表:因为查找的复杂性,使用很少,更多的是使用二叉链表,有时在不知道元素个数的情况下代替数组。
堆:快速查找最值。堆的存在说明了没有最好的数据结构,只是最合适的数据结构。
二叉树:普通二叉树由于不能保证最坏时间复杂度,使用很少,一般要使它平衡化。
图: 图的简单算法有最短路径,最小生成树,拓扑排序,图论是一个很大的研究领域,目前感觉应用图主要在于建模
并查集:一般意义上说,用于快速进行“连通性”判断。
Trie树:字符串查找树,适用于字符串比较短的情况。结点可以静态分配。
高级数据结构
平衡二叉树:比较有名的是AVL树,红黑树,伸展树,treap等。 Treap应用了随机化思想(《算法导论》习题)。伸展树应用了平摊分析思想。具体细节原理一个也说不上来,因为有了STL,有了map, 就懒得去理解了,得找时间自己实现一下。
可合并堆:应用了平衡设计的思想,保证堆的合并的最坏时间复杂度。算法导论介绍了两种,二项堆,斐波那锲堆。没做过相关题目。
线段树,树状数组:快速限定区间查找,为什么是线段树,不是线段图呢,为什么是树状数组不是其它什么状数组呢,这其实就是应用了平衡设计的思想,保证快速查找与维护。
RMQ:也是快速限定区间查找,但几乎不用维护,应用了平摊分析的思想。细节不明白,没做过相关题,有时间得研究下。
图论:最大流,最小费用最大流,应该属于算法类,关键在于建模。
二分图匹配:最大流的特殊情况,一般求二分图的最大匹配,建模。
STL:需要深入研究下。
离散数学是数据结构的基础。
算法:
基本算法
1:排序
归并排序:适用于对外部文件排序,也适用于对链表进行排序。
桶排序: 应用了hash思想,数据均匀分布时达到线性时间。
基数排序:基本非比较的线性时间排序算法,特殊的桶排序。
2:快速查找
一般有如下三种:
能用hash的就用hash,设计好的hash函数很重要
特殊的字符串查找可用trie树.
3:字符串匹配
KMP:单串匹配
Rabin-karp:思想很有意思
后缀数组:利用后缀的最长公共前缀进行字符串匹配。
AC自动机:对KMP的多串匹配的扩展
本领域一本专业书:《柔性字符串匹配》
4. :
高精度计算,加减乘除求幂等,有基本的规则可以套用。
高级算法:
高级算法很多都是在解组合最优化问题,这甚至有一个专门的学科叫运筹学,说组合数学是算法的基础也不为过吧。
把它看作一个类似于继承的类图。父方法一般能解决子方法能解决的问题(可能不是一般,很可能是少数情况,仅作方法间某种关系的描述,我的猜测而已)。而子方法能更好的解决有特殊性质的父方法能解决的问题。当然我们越使用下面的方法越好,如不行则考虑它的父方法。
1. 分治
快速排序及归并排序是分治的经典例子。从它的递归表达的时间复杂度(T(n)=2T(n/2)+O(n))来看,复杂度为O(n(lg(n)); 不过从它不能直观的表达分治为什么会快一些。以快速排序为例,
为什么分治会快些?简单的理解就是的当知道a>b 以及b>c 我们不用比较a与c也能知道a>c,这实际上是避免了一次不必要的比较。
分治有着三段式的使用结构:划分为不相交的子问题,处理子问题,合并子问题。
关键在于第一步,将大问题划为了不相交的子问题,减少了一个大问题间的有机联系,从而减少了一个问题的复杂度。以快排为例 从组合数学的角度来看,n个数之间的联系本为为C(n,2),但分割之后为C(n/2,2)+C(n/2,2)这样便减少了联系。
2. 动态规划
最优子结构+重叠子问题
最优子结构是为了保证算法的有效性,重叠子问题是保证动态规划能发挥自己填表记录的优势,不然也用不着动态规划了。《算法导论》对动态规划有着精彩的描述。
根据最优子结构推导出状态转移方程,状态转移方程可以使用自底向上的填表法计算,也可以采用自顶向下的备忘录方法计算,它还有一个名字,叫记忆化搜索,哪个方便使用哪个,不要拘泥于哪一个。
做了一二十道动态规划的题也只是对它有了初级的了解。。。。。。
1. 以背包、最大子段和为例的 线性组合动态规划
2. 以最长公共子序列、最优编辑为例的串类比较组合匹配动态规划。
3. 以矩阵链乘法、最优二叉树为例的区间组合动态规划
等等。。
动态规划经常是解决组合最优化问题,所以最好从组合的角度考虑状态转移方程,不过也很难想出来,囧。
4. 贪心
也是找最优子结构。。。能用贪心的就不要用动态规划了。
5. 搜索
如果上面的方法都不行,那只能搜索了。
搜索算法的套路很明显,知道一个问题是子集类问题或是一个排列类问题有助于我们编写相应的代码。
子集类问题 子集的数目:C(n,1)+C(n,2)+C(n,3)+…C(n,n)=2^n;
排列类问题 n排列数目 :n!
6.当自己用模拟做,别人可以用纯数学做时,感觉人与人之间的差距真不是一般的大。
其它:
数论:只知道最大公约数和素数检测
组合数学:做过很基础的题。
计算几何:完全没有涉及