第二次作业
1.找第 k 小的数的分治算法
1.选择数组(或当前区间)中的一个元素作为基准值。
2.对数组进行分区:将小于等于基准值的元素放到基准值左侧,大于等于基准值的元素放到右侧,得到基准值的最终位置。
3.计算基准值在当前区间中的 “排名”(即当前区间内基准值是第几个小元素)。
4.比较排名与 k:
若排名等于 k,基准值就是第 k 小的数,直接返回。
若排名大于 k,第 k 小的数在基准值左侧区间,递归处理左区间。
若排名小于 k,第 k 小的数在基准值右侧区间,递归处理右区间(此时 k 需减去左区间元素个数,即找右区间的第 k - 左区间长度小的数)。
5.重复上述步骤,直到区间缩小为单个元素(此时该元素就是目标)。
伪代码
plaintext
Function findKthSmallest(arr, left, right, k):
// 分:通过分区得到基准值位置
pivotPos = partition(arr, left, right)
// 计算基准值在当前区间的排名
rank = pivotPos - left + 1
// 治:根据排名判断目标位置
if rank == k:
return arr[pivotPos]
elif rank > k:
// 目标在左区间,递归处理左区间
return findKthSmallest(arr, left, pivotPos - 1, k)
else:
// 目标在右区间,递归处理右区间(调整k值)
return findKthSmallest(arr, pivotPos + 1, right, k - rank)
// 分区辅助函数(核心逻辑同之前代码)
Function partition(arr, left, right):
pivot = arr[left] // 选左端点为基准值
while left < right:
while left < right and arr[right] >= pivot:
right -= 1
arr[left] = arr[right]
while left < right and arr[left] <= pivot:
left += 1
arr[right] = arr[left]
arr[left] = pivot
return left
2. 算法时间复杂度分析
最好时间复杂度:O (n)
理想情况下,每次分区都能将数组分成大致相等的两部分(基准值是当前区间的中位数)。
第一次分区处理 n 个元素,第二次处理 n/2 个,第三次处理 n/4 个,以此类推,总操作次数为 n + n/2 + n/4 + ... + 1 ≈ 2n,时间复杂度为 O (n)。
最坏时间复杂度:O (n²)
最坏情况是每次分区都将数组分成 “极不均衡” 的两部分(如基准值是当前区间的最小值或最大值)。
第一次分区处理 n 个元素,第二次处理 n-1 个,第三次处理 n-2 个,以此类推,总操作次数为 n + (n-1) + (n-2) + ... + 1 = n (n+1)/2,时间复杂度为 O (n²)。
3.对分治法的体会和思考
找第 k 小元素的暴力解法是 “排序后取值”,时间复杂度 O (n log n),而分治法通过 “分区” 拆解问题,平均时间复杂度降至 O (n),效率大幅提升。
其本质是通过 “拆分” 缩小问题规模,将高复杂度的全局操作转化为低复杂度的局部操作,避免了对整个问题的 “一刀切” 处理。
浙公网安备 33010602011771号