又又又双双双叒叒叒叕叕叕是刷leetCode的题,(小知识:直接输入法youshuangruojue就是又双叒ruò叕jué啦)
之前第一次让我感觉到“排序算法还能这么用?”的的题是是topK问题(没听说过的小伙伴可以自己搜一下,网上很多),我大概描述一下就是给定一个数组,要求是取前k个数。
如果直接使用工具类的Arrays.sort()的话会多进行不少不必要的排序,就拿冒泡来说,他本来只需要冒k次就行了,你偏偏把他全部都排好了,完全没有必要。(只是用冒泡举个栗子,sort底层肯定不是用这个当然好多其他的算法都是可以通过自己的实现进行优化,每次到k就停止)。
这题对我最大的收获还是更加深刻的了解了快排,快排甚至不需要一个排列好的顺序,他的核心思想是取key每次快排移动key的位置,一次快排结束时保证key位置之前的都比他小,key之后的都比他大。这思想不时刚好吻合topK的思想吗?只需要最大的k个数,并不需要排序。一下子打开了新世界的大门。今天又做到一题,但是这题不是通过实现排序来优化逻辑,而是根本就没有可直接使用的api来排序,废话不多说直接上题
这题不是一道很难的题,思路也是很清晰的,主要是leetCode给的示例也是很好的,他直接给的就是两个已经是顺序结构的区间集,一看就知道顺序结构可以很好的理清区间覆盖的逻辑。
如上图,怎么判断是否需要覆盖呢?
区间1的右边界大于等于区间2的左边界的情况需要覆盖。
怎么覆盖呢?又有两种情况
①如上图,区间1的右边界小于区间2的右边界,这时候需要将区间1的右边界设置为区间2的右边界,再将区间2删除
②如下图,区间2的右边界小于区间1的右边界,这时候只需要将区间2删除即可
既然现在排好序的已经分析好情况了,我们就要思考了,输入的区间集一定是排好序的吗?明显题目中没有给出限定,那么这时候我们就需要自己将他进行排序了。而这一题的数组数据并不能 直接使用Arrays.sort()进行排序,所以就需要自己实现排序算法了。我选的当然是快排啦,快排牛逼—(声嘶力竭)
import java.util.*;
class Solution {
public int[][] merge(int[][] intervals) {
int len=intervals.length;
//base case
if(len==0)return intervals;
//按照区间的起始点排序
quickSort(intervals,0,len-1);
int []prev=intervals[0];
//记录结果数组中有多少的区间,从len开始每合并两个数组就减一
int count=len;
//这个for循环在合并区间
for(int i=1;i<len;i++){
int []cur=intervals[i];
if(prev[1]<cur[0]){
prev=cur;
continue;
}
if(cur[1]>prev[1])prev[1]=cur[1];
intervals[i]=null;
count--;
}
//结果数组
int ans[][]=new int[count][2];
//因为结果数组和intervals的遍历不是同步的所以需要
//额外添加结果数组的下标
int i=0;
//将intervals中非null的加入结果数组中
for(int j=0;j<len;j++){
if(intervals[j]!=null){
ans[i++]=intervals[j];
}
}
return ans;
}
//快排代码
private void quickSort(int[][] intervals,int left,int right){
if(left>=right)return;
int l=left;
int r=right;
int []key=intervals[l];
while(l<r){
while(l<r&&intervals[r][0]>=key[0]){
r--;
}
intervals[l]=intervals[r];
while(l<r&&intervals[l][0]<=key[0]){
l++;
}
intervals[r]=intervals[l];
}
intervals[l]=key;
quickSort(intervals,left,l-1);
quickSort(intervals,r+1,right);
}
}