分治
- 找第k小数的分治算法
可以使用“快速选择(Quickselect)”算法。其基本思想是:先从数组中选取一个基准元素pivot,然后将数组划分为小于pivot、等于pivot和大于pivot的三部分。
设小于pivot的元素个数为m:
如果k小于或等于m,说明第k小的数在小于pivot的部分中,继续在该部分递归查找。
如果k大于m且不超过“小于pivot的元素个数加上等于pivot的元素个数”,说明pivot就是第k小的数。
否则,第k小的数在大于pivot的部分中,继续在该部分查找第k-m-等于pivot元素个数小的数。
伪代码如下:
Select(A, k)
如果A中只有一个元素
返回A[0]
从A中选择一个元素作为pivot
L = A中所有小于pivot的元素
E = A中所有等于pivot的元素
R = A中所有大于pivot的元素
如果k <= L的长度
返回Select(L, k)
如果k <= L的长度 + E的长度
返回pivot
返回Select(R, k - L的长度 - E的长度)
- 时间复杂度分析
每次划分数组时,都需要遍历当前数组中的元素,因此一次划分操作的时间复杂度为O(n)。
最好情况下,每次选择的pivot都能将数组较均匀地划分为两部分。此时递推式为:
T(n) = T(n/2) + O(n)
因此,最好时间复杂度为O(n)。
最坏情况下,每次选择的pivot都是当前数组中的最小值或最大值。这样每次只能排除一个元素,递推式为:
T(n) = T(n-1) + O(n)
因此,最坏时间复杂度为O(n²)。
如果随机选择pivot,快速选择算法的期望时间复杂度通常为O(n)。
- 对分治法的体会和思考
分治法是一种把复杂问题逐步分解为规模更小、结构相似的子问题,再通过递归或合并得到原问题答案的算法思想。它的关键在于合理地划分问题,使每个子问题都比原问题更容易处理。
在找第k小数的问题中,不需要像排序算法那样把所有元素完全排序,只需要根据pivot的位置判断答案在哪一部分,并继续处理这一部分即可。这说明设计算法时,应尽量避免无关的计算,只保留解决问题所必需的信息。
同时,分治法的效率与划分是否均衡密切相关。若每次划分比较均匀,算法效率较高;若划分极不均匀,算法效率可能明显下降。因此,在实际应用中,选择合适的划分方法和基准元素十分重要。
通过学习分治法,我认识到,面对复杂问题时,可以先将问题拆分,再逐步解决各个部分。合理的分解不仅能降低问题难度,也能够提高算法效率。

浙公网安备 33010602011771号