堆排序的应用-计算最大线段重合数问题java

最大线段重合数

给定很多线段,每个线段都有两个数[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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值