乘着上的算法导论课还有些映象,做一些记录。
- 贪心算法
- 分治法
- 动态规划
- 自顶向下
- 自底向上
- NP问题,规约
- 近似算法
- load balancing
贪心算法
it buids up a solution in small steps,choosing a desicion at each step myopically(目光短浅地) to optimize some unerlying criterion(标准)
简而言之:由局部最优—>全局最优. 有时不存在
典型问题:Interval Scheduling
* starts first(x)
* smallest interval of time (x)
* fewest conflicts (x)
* accept the request that finishes first (yes) [O(n*logn)]
Divide and conquer (分治法)
核心思想在于把输入分成若干部分,递归地求解每个部分的问题,然后把这些子问题的解组合为一个全局的解。个人以为分治法与动态规划的使用区别主要在于分解的子问题是否相关,若可以将原问题分解成多个互相不相干的子问题则可以使用分治法,否则不能使用分治法,若子问题相关可以考虑动态规划。
1. Divide:divide the problem into one or more subproblems
2. Conquer:conquer each subproblems recursively.
3. combine:solution.
eg.* 归并排序,快速排序。
* 二分查找(binary search)
* Powering a number(乘方问题)
* Fibonacci number(斐波那契数列):Bottom-up,
* Matrix:n*n matrix = 2*2 block matrix of n/2*n/2 sub matrices
动态规划(Dynamic Programming)
Basic principle for dynamic programming:Iterating over subproblems rather than computing solutions recursively。
经典问题:Subset sums(子集合求和) 和Knapsacks(背包问题),Weighted Interval Schedule。
排序与查找算法
常用的排序算法:
1. 选择排序:每次选index右侧集合最小的插入当前index位置,向右(数组尾端)移动index 适用于小数组
2. 插入排序:适合已经部分有序(倒置少的)的数列。 适用于小数组。
3. 希尔排序:高效算法,不需要理解它的性能。对于各种数组均有较好的表现。 最好手写
4. 归并排序:将两个有序数组归并成一个更大的有序数组。
先递归地将它分成两半排序, 然后将结果归并起来。时间:O(N*logN),空间:O(N)
运用了分治的思想。不适用与小数组
5. 快速排序:分治的排序算法,将一个数组切分成两个子数组, 将两部分独立地进行排序。如何进行切分是快速排序的关键。每一次切分都是将切分元素j放到了排序的最终位置,且a[lo..j-1]<= a[j] <=a[j+1…hi] ,经典问题求解中位数或第k大的数:利用切分思想而不是完全使用快排(不需要完全排序)。
6. 堆排序:典型用例,基于二叉堆求解Top K问题。非常适合数据量非常大的场合。
时间复杂度和空间复杂度比较:
排序方法 | 平均时间 | 最差时间 | 额外空间 | 稳定度 | 备注 |
---|---|---|---|---|---|
选择排序 | O(n^2) | O(n^2) | O(1) | 不稳定 | 适合小n |
插入排序 | O(n^2) | O(n^2) | O(1) | 稳定 | 适合基本有序,倒置少的数据 |
归并排序 | O(nlogn) | O(nlogn) | O(n) | 稳定 | 适合大n(因为递归) |
快速排序 | O(nlogn) | O(n^2) | 取决于算法,空间消耗多在递归栈中 | 不稳定 | 算法的效率依据是概率,适合大n(递归),在数据基本有序时效率低。 |
堆排序 | O(nlogn) | O(nlogn) | O(1) | 不稳定 | 适合n非常大时,上述归并和快排可能空间消耗溢出,而堆排序则非常合适,常见求解问题:Top K问题 |
查找
三种经典的数据类型:
1. 二叉查找树:理想状态复杂度为logN,但由于插入可能不平衡,导致最坏结果可能复杂度为N(形成一个链表模式)。
2. 红黑树:平衡树,在插入和删除时保持平衡(通过旋转和改变链接的颜色), 由此实现了查找复杂度为logN. 定义为含有红黑链接并满足下列条件的二叉查找树:
1. 红链接均为左链接。
2. 没有任何一个结点同时和两个红链接相连。
3. 任意空链接到根节点的路径上的黑链接数量相同。
3. 散列表 :例如HashMap,hash函数将键转化为数组的索引,Java中的HashMap中散列函数:将处理后的key的hashcode做散列:index = hash(key) & table.length - 1,即key的hash值与数组长度-1做与运算,与取余法有同样的结果但效率更高(因为&运算比%运算效率高)而且java中取余的结果可能为负。解决冲突的方式:常用的为链表法(即拉链法),还有线性探测法。
散列表的查找比红黑树更快吗?
这取决于键的类型,它决定了hash的计算成本是否大于compareTo的比较成本。对于常见的键类型以及Java的默认实现,这两者的成本是近似的,因此散列表会比红黑树快很多,因为它所需的操作次数是固定的。