- 找第 (k) 小的数的分治算法
可以借用快速排序中划分数组的方法。先选一个基准元素,例如当前区间的第一个数,通过一次划分,把小于等于基准的数放在左边,大于等于基准的数放在右边,并确定基准的位置 (p)。
假设当前区间为 ([left,right]),则基准在这个区间中的排名为 (rank=p-left+1)。如果 (rank=k),基准就是要找的数,直接返回;如果 (rank>k),就在左边的区间继续找第 (k) 小的数;如果 (rank<k),就在右边的区间找第 (k-rank) 小的数,因为前面已经排除了 (rank) 个数。
重复这个过程,不断缩小查找范围,直到找到目标,或者区间中只剩下一个数。与快速排序相比,这个算法每次只需要处理目标所在的一边,不用把整个数组排好序。
- 最好时间复杂度和最坏时间复杂度
最好时间复杂度为 (O(n))。如果第一次划分后,基准恰好就是第 (k) 小的数,只需遍历一次数组就能得到答案。如果每次划分都比较均匀,每次只需继续处理大约一半的数据,总计算量为 (n+n/2+n/4+ldots),时间复杂度 同样是 (O(n))。
最坏时间复杂度为 (O(n^2))。当每次选到的基准都是当前区间的最小值或最大值,而且目标一直在剩下的那一边时,每次只能排除一个元素,需要处理的规模依次为 (n,n-1,n-2,ldots),总计算量为平方级。例如,数组已经有序,每次固定选择第一个元素作为基准,并查找靠后的元素,就可能出现这种情况。
- 对分治法的体会和思考
通过本章的学习,我觉得分治法主要是把一个规模较大的问题拆成更小的同类问题,再通过求解子问题得到原问题的答案。刚开始接触递归时,我容易把注意力放在函数怎样调用自己上,后来发现,更关键的是想清楚如何划分问题,以及什么时候可以直接得到结果、结束递归。
找第 (k) 小的数这个例子让我认识到,并不是划分出来的每一部分都要继续处理。根据基准的排名,就能排除一部分数据,减少不必要的计算。同时,划分方式也会影响效率,同一个算法可能是 (O(n)),也可能退化为 (O(n^2))。所以在使用分治法时,既要保证子问题划分正确,也要考虑每次能缩小多少规模,不能只看算法用了递归就认为它一定高效。
posted @
2026-10-07 23:11
Akiooo
阅读(
6)
评论()
收藏
举报