LeetCode 912
https://leetcode.cn/problems/sort-an-array/description/
难度:中等
高频面试题汇总:https://www.yuweihung.com/posts/2025/lc-hot/
本题是手撕堆排序,使用最大堆。在本题中因为不会有新的元素插入,只需要实现自顶向下修复堆的操作即可。建堆时从最后一个非叶子结点开始,依次调用 repair 函数。然后每次将堆顶元素与堆的最后一个元素交换,堆的大小减一,修复堆。最后数组即为升序排列。反之,如果降序排列使用最小堆。
时间复杂度:O(nlogn)。初始化建堆的时间复杂度为 O(n),建完堆以后需要进行 n−1 次调整,一次调整的时间复杂度为 O(logn),那么 n−1 次调整即需要 O(nlogn) 的时间复杂度。因此,总时间复杂度为 O(n+nlogn)=O(nlogn)。
空间复杂度:O(1)。只需要常数的空间存放若干变量。
class Solution {
private:
int tot = 0;
// 自顶向下修复堆
void repair(vector<int>& nums, int x) {
if (x * 2 + 1 >= tot) {
return;
}
int tar = x * 2 + 1;
if (x * 2 + 2 < tot) {
tar = nums[x * 2 + 1] > nums[x * 2 + 2] ? x * 2 + 1 : x * 2 + 2;
}
if (nums[x] < nums[tar]) {
swap(nums[x], nums[tar]);
repair(nums, tar);
}
}
// 堆排序函数
void heapSort(vector<int>& nums) {
int n = nums.size();
tot = n;
// 构建最大堆:从最后一个非叶子节点开始
for (int i = n / 2 - 1; i >= 0; i--) {
repair(nums, i);
}
// 依次提取最大值并放到数组末尾
for (int i = n - 1; i > 0; i--) {
swap(nums[0], nums[i]); // 将最大值移到数组末尾
tot--;
repair(nums, 0); // 调整剩余堆(大小为i)
}
}
public:
vector<int> sortArray(vector<int>& nums) {
heapSort(nums);
return nums;
}
};