今天看了左程云算法课021,复习了归并排序。在这节课中有两种实现归并排序的方式,分别是递归实现和迭代实现。从算法通过的角度来看,只重点看递归实现。(短期内我的目标比较明确,就是能够算法通过,并不适合地毯式学习)。
左程云的算法课到今天为止先暂停,左神算法课适合长时间的打基础,比较适合面向秋招(估计明年春季会继续地毯式复习)。目前需要一个月内打通实习面试算法题,在前期左神课程打了一部分代码基础之后开始刷力扣hot100。
回到今天课程内容上,那么递归实现的的核心思想就是:左部排好序,右部排好序,然后利用Merge过程让左右都整体有序。Merge过程的核心思想:左右两部分各有一个指针,谁小就拷贝到临时数组中,知道左右两部分所有数组耗尽,最后将临时数组拷贝回原数组中。
那么归并排序的递归实现的时间复杂度是O(nlogn),需要辅助数组,所以额外的空间复杂度为O(n)。思考归并排序为什么比三傻排序要快,除了从时间复杂度上能看出来,从算法过程来看,归并排序的比较行为没有浪费,就是每一步比较之后都是有操作的,比较完后也有一个相对有序的中间结果,而不像三傻排序,遍历比较所有但只能确定一个数的位置。后面左神算法课022是将本节内容拓展成归并分治(用归并思想来解决问题,并且要学会思考什么问题可以用归并来解决),比较高级。但是后续再说。
那么归并排序的代码如下(填代码版),需要将辅助数组help设置成全局静态变量,否则运行会超时,每次都开辟空间会比较耗时,因此只开辟一块全局变量来共同使用,空间和时间都有优化:
class Solution {
public static int MAXN=50001;
public static int[] help=new int[MAXN];
public int[] sortArray(int[] nums) {
MergeSort(nums,0,nums.length-1);
return nums;
}
public void MergeSort(int[] nums,int l, int r){
if(l==r){
return;
}
int mid=l+(r-l)/2;
MergeSort(nums,l,mid);
MergeSort(nums,mid+1,r);
Merge(nums,l,r,mid);
}
public void Merge(int[] nums,int l,int r,int mid){
int a=l;
int b=mid+1;
int i=l;
//int[] help=new int[nums.length];
while(a<=mid && b<=r){
help[i++]=nums[a]<=nums[b]?nums[a++]:nums[b++];
}
while(a<=mid){
help[i++]=nums[a++];
}
while(b<=r){
help[i++]=nums[b++];
}
//替换
for(i=l;i<=r;i++){
nums[i]=help[i];
}
}
}