description
function: Select(A, k) Input: array A of numbers, and an integer . Output: the k-th smallest number in A.
一种方法就是先排序然后选择第k个,时间复杂度O(nlog(n))
Solution
stanford 笔记地址 PDF
从特殊到一般:
最小元素(k=1)
非常直接的思路就是逐个遍历然后更新最小值,时间复杂度O(n) 这谁都会嘛 :D

第二小元素(k=2)
还是很简单,使用两个参数存最小的和第二小的不就行了吗?
中位数(k=)
这时候,如果使用数组的话,我们就进入了一个插入排序的陷阱,复杂度就会上升到O(n^2)了
分治
思路
- 我要第 个最小的,关你后 个最大的什么事?
- 我要第 个最小的,不需要知道它之前的元素顺序
可以想办法从逻辑上去除(忽略)后 个最大的。怎么去除呢?
可以随便选择一个点pivot,让小于这个点的移到左边,大于的移到右边(复杂度O(n))
假设把 个元素划分到了左边,划分到左边的数组记作 ,划分到右边的记作 ,那么问题就转换为了子问题:
- select(A,k)
- pivot,
- select(, k),
- select(, ),
复杂度分析
整个程序的复杂度如下:
这里的 len(L/R) 表示划分后数组大小。
- 在理想情况下,每次都将数组切成两半,那么用主定理算出来复杂度是
- 在最差情况下(每次都选到最大/最小值),复杂度就是O(N^2)了
-
pivot选取
至于pivot怎么选择,其实只要运气不太差,复杂度就还是O(n)的。这个差运气的概率为 ,除非测试用例故意搞你,几乎不可能发生:P
cs161给出的做法是划分几个小区快,从这些区块中选择 povit*,在这些 povit*中选择最终的 povit

