912.排序数组
912.排序数组
题目
给你一个整数数组 nums,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 5 * 104
-5 * 104 <= nums[i] <= 5 * 104
通过次数260,242提交次数466,830
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
归并排序
归并排序,当我们需要排序一个数组时,先将数组分成一半,然后想办法把左边的数组给排序,右边的数组给排序,之后再将它们归并起来。那现在对数组的排序就变成了对左边数组的排序和右边数组的排序。
当然了当我们对左边的数组和右边的素组进行排序的时候,再分别将左边的数组和右边的数组分成一半,然后对每一个部分先排序,再归并。如图:

什么时候停止递归,只有一个元素时已经有序了,就不用再排序了,直接归并就好了。
这个思路不就是递归的思路吗!归并的过程就是在递归。
归并算法的实际复杂度 O(nlogn),递归的深度是logn 合并的的时间复杂度是n
使用递归三部曲解题
递归的参数和返回值
我们这个返回void直接对nums进行修改。
参数需要原数组和两个划分区间的指针left、right
void merge (int[]nums,int left,int right){
}
递归的终止条件
只有一个元素时,自然就是有序的
if(left==right) return;
本层递归需要做什么
本层递归需要把有序的两个部分合并成有序的一个部分。
public int[] sortArray(int[] nums) {
int len = nums.length;
merge(nums,0,len-1);
return nums;
}
void merge (int[]nums,int left,int right){
int mid = (left+right)>>2; //除以2的操作
merge(nums,left,mid); //左边的有序数组
merge(nums,mid+1,right);//右边的有序数组
// 如果数组的这个子区间本身有序,无需合并!!!这里是一个优化
if (nums[mid] <= nums[mid + 1]) {
return;
}
//对l1和l2进行合并
mergeSort(nums,left,mid,right); //左右两边有序合成一个有序数组
}
//合并两个
void mergeSort(int[] nums,int left,int mid,int right){
int l = left, m = mid +1;
int k = 0;
int [] arr = new int[right-left+1]; //记录排好序的结果
while(l<=mid && m<=right){
//相同元素原来靠前的排序以后依然靠前,所以这里必须写成<=才能保证稳定性
if(nums[l]<=nums[m]) arr[k++] = nums[l++];
else arr[k++] = nums[m++];
}
//把左右两个数组剩下的元素放入数组
while(l<=mid){
arr[k++] = nums[l++];
}
while(m<=right){
arr[k++] = nums[m++];
}
for(int i=0;i<arr.length;i++){ //新数组覆盖老数组
nums[left+i] = arr[i];
}
}
复杂度分析
- 时间复杂度:O(NlogN),这里 NN 是数组的长度;
- 空间复杂度:O(logN),这里占用的空间主要来自递归函数的栈空间。
浙公网安备 33010602011771号