912. 排序数组 - 力扣(LeetCode)912. 排序数组 - 给你一个整数数组 nums,请你将该数组升序排列。你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(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 * 104 * -5 * 104 <= numsi <= 5 * 104
https://leetcode.cn/problems/sort-an-array/description/
归并排序
一、核心思想
分治思想
- 分 :把待排序数组不断对半拆分,直到每个子序列只有1 个元素(天然有序);
- 治(归并):将两个有序子数组合并成一个更大的有序数组;
- 递归重复,最终合并得到完整有序数组。
一句话总结:先拆分,分到最小单元,再两两有序合并。
cpp
[38,27,43,3,9,82,10]
[38,27,43] [3,9,82,10]
[38,27] [43] [3,9] [82,10]
[38] [27] [3][9] [82][10]
cpp
[38][27] → [27,38]
[27,38] + [43] → [27,38,43]
[3][9] → [3,9]
[82][10] → [10,82]
[3,9] + [10,82] → [3,9,10,82]
[27,38,43] + [3,9,10,82] → [3,9,10,27,38,43,82]
很像是二叉树的后序遍历
而快排则是像二叉树的前序遍历
题目描述
题目要求:给你一个整数数组
nums,请你将该数组升序排列。你必须在不使用任何内置排序函数的情况下解决问题,时间复杂度要求 \(O(n\log n)\),空间复杂度尽可能小。
关键:合并两个有序数组
合并逻辑是归并排序最重要的模块: 输入两段有序区间 [l, mid]、[mid+1, r]
- 开辟临时数组存放合并结果;
- 双指针分别指向两段有序区间起点;
- 比较两个指针指向元素,把更小的值放入临时数组,对应指针后移;
- 其中一段遍历完成后,直接追加另一段剩余元素;
- 将临时有序数组覆盖回原数组对应区间。
cpp
class Solution {
public:
vector<int> temp;
vector<int> sortArray(vector<int>& nums) {
int n=nums.size();
temp.resize(n);
mergesort(nums,0,n-1);
return nums;
}
void mergesort(vector<int>& nums,int left,int right)
{
if(left >= right) return;
int mid=(left+right)/2;
mergesort(nums,left,mid);
mergesort(nums,mid+1,right);
int cur1=left,cur2=mid+1,i=0;
while(cur1<=mid&&cur2<=right)
temp[i++]=nums[cur1]<nums[cur2]?nums[cur1++]:nums[cur2++];
while(cur1<=mid)
temp[i++]=nums[cur1++];
while(cur2<=right)
temp[i++]=nums[cur2++];
for(int i=left;i<=right;i++)
{
nums[i]=temp[i-left];
}
}
};