最大线段重合数
给定很多线段,每个线段都有两个数[start, end], 表示线段开始位置和结束位置,左右都是闭区间 规定:
1.线段的开始和结束位置一定都是整数值
2.线段重合区域的长度必须>=1
3.返回线段最多重合区域中,包含了几条线段
暴力解决方案
暴力方法就很好理解了,我们首先找到所有线段的最小起点,和最大终点.然后去遍历排序好的线段,以0.5为考察值,每次增加1,来遍历每个区间内有多少重合线段
时间复杂度O(n2)
直接上代码演示
/**
* 直接遍历去判断
* @param lines
* @return
*/
public static int maxCover1(int[][] lines) {
//把线段最小起点和最大终点找到.
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < lines.length; i++) {
min = Math.min(min, lines[i][0]);
max = Math.max(max, lines[i][1]);
}
int cover = 0;
//由于重合长度最小是1,所以我们选择中间值来判断有多少线段重合,当然0.3都是可以的.
//先遍历所有可能重合的区间
for (double p = min + 0.5; p < max; p += 1) {
int cur = 0;
//再遍历所有的线段
for (int i = 0; i < lines.length; i++) {
if (lines[i][0] < p && lines[i][1] > p) {
cur++;
}
}
cover = Math.max(cover, cur);
}
return cover;
}
采用堆排序来优化下算法
解题思路:
1.我们先把所有线段的以开始位置排个序,
2.再用小根堆来依次加入每条线段的终点位置,加入时,要注意:
a.要看下堆里的元素有没有比当前线段起始位置小的数字,有的话就弹出.
b.弹出以后,就把该线段的终点位置加进堆里,此时堆里有几个数字,代表重合了几条线段.
如何理解:
上面流程说完了,为什么这样可以得出重合线段呢.
首先我们想一个问题,按起始位置拍好序的线段,堆里加的是之前线段的终点位置,那么如果终点位置有小于等于当前线段的起始位置,说明不可能重合,那么弹出,剩下的就都是会重合的.
还是上代码,根据代码来理解思路,互相印证
public static int maxCoverHeap(int[][] m) {
// m是二维数组,可以认为m内部是一个一个的一维数组
//这是语法糖的写法,a,b 相当于二维数组中的一个元素,
//也就是一位数组,[start,end]线段的起始和终点位置
//下面这样写就是根据起始位置排好序了
Arrays.sort(m, (a, b) -> (a[0] - b[0]));
// 准备好小根堆.
PriorityQueue<Integer> heap = new PriorityQueue<>();
int max = 0;
for (int[] line : m) {
while (!heap.isEmpty() && heap.peek() <= line[0]) {
heap.poll();
}
heap.add(line[1]);
max = Math.max(max, heap.size());
}
return max;
采用堆排序优化后,时间复杂度变成了O(n*logN)