Medium
题目描述
给你一个整数数组 nums,请你将该数组升序排列并返回。
你必须在不使用任何内置函数的情况下解决问题,时间复杂度为 O(n log n),并且空间复杂度尽可能小。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
解释:排序后,某些数字的位置没有改变(例如 2 和 3),而另一些数字的位置发生了改变(例如 1 和 5)。
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
解释:注意 nums 的值不一定是唯一的。
提示:
1 <= nums.length <= 5 * 10^4-5 * 10^4 <= nums[i] <= 5 * 10^4
解题思路
本题要求在不使用内置排序函数的情况下,以 O(n log n) 时间复杂度对数组进行排序。根据约束条件,有几种经典的排序算法可以选择:
方法一:归并排序(推荐) 归并排序采用分治思想,将数组递归地分成两半,分别排序后再合并。它保证稳定的 O(n log n) 时间复杂度,空间复杂度为 O(n)。归并排序的优点是性能稳定,不受输入数据影响。
方法二:快速排序 快速排序通过选择基准值进行分区,平均时间复杂度为 O(n log n),但最坏情况下为 O(n²)。为了避免最坏情况,可以使用随机化或三数取中法选择基准。
方法三:堆排序 构建最大堆后依次取出堆顶元素,时间复杂度稳定为 O(n log n),空间复杂度为 O(1)。
方法四:计数排序 由于题目给出了数值范围(-50000 到 50000),可以使用计数排序达到 O(n + k) 的时间复杂度,其中 k 为值域大小。
考虑到题目要求空间复杂度尽可能小且时间复杂度稳定,这里推荐使用归并排序作为主要解法。
代码实现
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
private:
void mergeSort(vector<int>& nums, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
merge(nums, left, mid, right);
}
void merge(vector<int>& nums, int left, int mid, int right) {
vector<int> temp(right - left + 1);
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= right) temp[k++] = nums[j++];
for (int i = 0; i < temp.size(); i++) {
nums[left + i] = temp[i];
}
}
};
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def merge_sort(arr, left, right):
if left >= right:
return
mid = (left + right) // 2
merge_sort(arr, left, mid)
merge_sort(arr, mid + 1, right)
merge(arr, left, mid, right)
def merge(arr, left, mid, right):
temp = []
i, j = left, mid + 1
while i <= mid and j <= right:
if arr[i] <= arr[j]:
temp.append(arr[i])
i += 1
else:
temp.append(arr[j])
j += 1
while i <= mid:
temp.append(arr[i])
i += 1
while j <= right:
temp.append(arr[j])
j += 1
for k in range(len(temp)):
arr[left + k] = temp[k]
merge_sort(nums, 0, len(nums) - 1)
return nums
public class Solution {
public int[] SortArray(int[] nums) {
MergeSort(nums, 0, nums.Length - 1);
return nums;
}
private void MergeSort(int[] nums, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
MergeSort(nums, left, mid);
MergeSort(nums, mid + 1, right);
Merge(nums, left, mid, right);
}
private void Merge(int[] nums, int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= right) temp[k++] = nums[j++];
for (int idx = 0; idx < temp.Length; idx++) {
nums[left + idx] = temp[idx];
}
}
}
var sortArray = function(nums) {
function mergeSort(arr, left, right) {
if (left >= right) return;
const mid = Math.floor((left + right) / 2);
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
function merge(arr, left, mid, right) {
const temp = [];
let i = left, j = mid + 1;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp.push(arr[i++]);
} else {
temp.push(arr[j++]);
}
}
while (i <= mid) temp.push(arr[i++]);
while (j <= right) temp.push(arr[j++]);
for (let k = 0; k < temp.length; k++) {
arr[left + k] = temp[k];
}
}
mergeSort(nums, 0, nums.length - 1);
return nums;
};
复杂度分析
| 算法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 归并排序 | O(n log n) | O(n) |
| 快速排序(平均) | O(n log n) | O(log n) |
| 快速排序(最坏) | O(n²) | O(n) |
| 堆排序 | O(n log n) | O(1) |
| 计数排序 | O(n + k) | O(k) |
其中 n 为数组长度,k 为值域范围(本题中 k = 100001)。