13.5: 最大线段重合问题(堆实现),敏感度

13.5: 最大线段重合问题(堆实现),敏感度

 

  给定很多线段,每个线段都有左右两个位置 [ start,  end ],表示线段开始位置和结束位置,左右都是闭区间,

规定:

  1、线段的开始和结束位置一定都是整数值;

  2、线段重合区域的长度必须 >= 1,一个点不算重合区域;

  线段 a [1, 3]

     b [3, 6] ,不算重合区域,只重合了一个点3。

要求返回线段最多重合区域中,包含了几条线段。

比如:

  a [ 1 , 8 ]

  b [ 2 , 6 ]

  c [ 3, 10 ]       数轴上画图,返回线段最多重合区域中,包含了几条线段。

 

 

暴力解法:

  每个线段都有开始和结束位置,

找所有的线段中开始最小的位置(min开)

找所有的线段中结束最大的位置(max结),此时所有线段都在[ min开, max结 ]这个线段上,

看看有多少线段是包含min开 + 1.5, 包含min开 + 2.5,包含min开 + 3.5 ,包含min开 + 4.5......

 (不要写成整数,写成整数会出现只重合一个点的问题),

找其中最大值。

时间复杂度O( (max - min) * N)

 

 

复制代码
 1     public static int maxCover1(int[][] lines) {
 2         
 3         int min = Integer.MAX_VALUE;
 4         int max = Integer.MIN_VALUE;
 5         
 6         for (int i = 0; i < lines.length; i++) {     
 7             min = Math.min(min, lines[i][0]);        //求出每条线段的左端最小值
 8             max = Math.max(max, lines[i][1]);         //求出每条线段的右端最大值
 9         }
10         
11         int cover = 0;
12         for (double p = min + 0.5; p < max; p += 1) {   //从p位置开始直到max,0.5 1.5 2.5 ..... 99.5的距离去探测
13             int cur = 0;
14             for (int i = 0; i < lines.length; i++) {    //对于每条线段,p点在里面,计数器++
15                 if (lines[i][0] < p && lines[i][1] > p) {
16                     cur++;
17                 }
18             }
19             cover = Math.max(cover, cur);                  //内循环一遍结束后,得到:p点在多少条线段中。外循环结束,得到包含p最多的条数。
20         }
21         return cover;
22     }
复制代码

 

 

 

 

 

 

用堆实现的流程:

  所有线段,先根据每个线段的开始位置排序,从小到大,

准备小根堆,目前为空,依次考察每一个线段,按下方思路操作。

线段[ 1, 7 ]         1、把堆中    <= 1的数弹出                 2、把结尾7放入小根堆       3、现在小根堆中有[ 7 ],此时有1个数

  多解释一下“此时有1个数”:

       表示重合区域必须以我这个1为左边界的话,往右延伸了多少条线段。

       

 

线段[ 2, 3 ]         1、把堆中    <= 2的数弹出                 2、把结尾3放入小根堆       3、现在小根堆中有[ 3 7 ],此时有2个数

   多解释一下:

       为什么先检查一下小根堆中有多少是小于2的,为什么检查?

        如果结尾小于等于2,这个线段[ 2, 2 ]穿不过2,就不是线段了。

        把4放进去,堆中的数为2.说明已2为左边界的线段有2条。

 

线段[ 4, 6 ]         1、把堆中    <= 4的数弹出 ,3出       2、把结尾6放入小根堆       3、现在小根堆中有[ 6 7 ],此时有2个数

线段[ 4, 5 ]         1、把堆中    <= 4的数弹出 ,             2、把结尾5放入小根堆       3、现在小根堆中有[ 5 6 7 ],此时有3个数

所有线段的答案都求出来,找最大的那个,就是最大线段重合数。

 

 

任何一个重合区域的左边界必是某个线段的左边界

考察每一个线段的左边界,假设它是重合区域的左边界,求出从这个左边界开始向右的贯穿数,答案必是那个最大的数。

O(N * logN)

复制代码
1 public static class Line {
2         public int start;
3         public int end;
4 
5         public Line(int s, int e) {
6             start = s;
7             end = e;
8         }
9     }
复制代码
public static class StartComparator implements Comparator<Line> { 
  @Override 
  
public int compare(Line o1, Line o2) {
    
return o1.end - o2.end;
   }
}
复制代码
 1 public static int maxCover2(int[][] m) {
 2         Line[] lines = new Line[m.length];
 3         for (int i = 0; i < m.length; i++) {
 4             lines[i] = new Line(m[i][0], m[i][1]);
 5         }
 6         Arrays.sort(lines, new StartComparator());
 7         // 小根堆,每一条线段的结尾数值,使用默认的
 8         PriorityQueue<Integer> heap = new PriorityQueue<>();
 9         int max = 0;
10         for (int i = 0; i < lines.length; i++) {
11             // lines[i] -> cur 在黑盒中,把<=cur.start 东西都弹出
12             while (!heap.isEmpty() && heap.peek() <= lines[i].start) {
13                 heap.poll();
14             }
15             heap.add(lines[i].end);
16             max = Math.max(max, heap.size());
17         }
18         return max;
19     }
复制代码

 

posted @   yzmarcus  阅读(249)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示