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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

归并排序

归并排序,当我们需要排序一个数组时,先将数组分成一半,然后想办法把左边的数组给排序,右边的数组给排序,之后再将它们归并起来。那现在对数组的排序就变成了对左边数组的排序和右边数组的排序。

当然了当我们对左边的数组和右边的素组进行排序的时候,再分别将左边的数组和右边的数组分成一半,然后对每一个部分先排序,再归并。如图:

image

什么时候停止递归,只有一个元素时已经有序了,就不用再排序了,直接归并就好了。

这个思路不就是递归的思路吗!归并的过程就是在递归。

归并算法的实际复杂度 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),这里占用的空间主要来自递归函数的栈空间。

快速排序

posted @ 2021-12-24 16:31  rananie  阅读(63)  评论(0)    收藏  举报