package class07; import java.util.Arrays; import java.util.Comparator; import java.util.PriorityQueue; /** * 最多线段重合问题(堆实现的方式) * <p> * 给定很多线段,每个线段都有两个数[start, end], * 表示线段开始位置和结束位置,左右都是闭区间 * 规定: * 1)线段的开始和结束位置一定都是整数值 * 2)线段重合区域的长度必须>=1 * 返回线段最多重合区域中,包含了几条线段 */ public class Code01_CoverMax { //获取重合的线段最多有多少条。 //效率低的方法。机器笔试时可能可以通过,但是面试时这种方法不通过,没分。 private static int CoverMax1(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; //定义一个不是整数的数,把经过此数的线段的条数,汇总累加到cover上。 for (double p = min + 0.5; p < max; p++) { int cur = 0; for (int i = 0; i < lines.length; i++) { //当一条线段的开始值小于p,并且结束值大于p时,将cur++。 //表示经过p这个小数的线段,有cur条。 if (lines[i][0] < p && lines[i][1] > p) { cur++; } } //对于此次循环的小数p,当所有线段都走了一遍时,看看时当前的cur大,还是之前的线段累加和cover大。 //获取一个较大的值,作为cover。即更新"重合的线段最多的条数"。 cover = Math.max(cover, cur); //此时p要++了,即换下一个小数p,看看经过p的线段共有多少条。 } return cover; } //用堆实现的方式 public static int CoverMax2(int[][] m) { //先定义一个Line类型,再定义一个Line类型的数组。 Line[] lines = new Line[m.length]; for (int i = 0; i < m.length; i++) { lines[i] = new Line(m[i][0], m[i][1]);//给lines数组的每一个元素赋值。 } Arrays.sort(lines, new StartComparator());//使用自定义比较器,给lines数组排序。 //定义优先级队列,使用默认的小根堆,即最小值在最上边。将每次循环的线段的结束值加入进去。 PriorityQueue<Integer> heap = new PriorityQueue<>(); int max = 0; for (int i = 0; i < lines.length; i++) { //当heap不为空,并且heap的栈顶,即最小值小于等于,当前循环中的线段的开始值时。 while (!heap.isEmpty() && heap.peek() <= lines[i].start) { heap.poll();//弹出heap的栈顶,即最小值。 } heap.add(lines[i].end);//往heap中添加当前循环的线段的结束值。 max = Math.max(max, heap.size());//更新heap的个数。把较大的数赋值给max。 } return max;//返回最大的heap的个数,就是结果。 } //和CoverMax2()的过程一样,只是CoverMax3()的代码更短,没有使用类定义的方式。 public static int CoverMax3(int[][] m) { //m是二维数组,可以因为m内部是一个一个的一维数组。 //每一个一维数组就是一个对象,也就是线段。 //下边的code,就是根据每一个线段的开始值升序排序。 Arrays.sort(m, (a, b) -> (a[0] - b[0])); //定义小根堆。 PriorityQueue<Integer> heap = new PriorityQueue<>(); int max = 0; for (int[] line : m) { if (!heap.isEmpty() && heap.peek() <= line[0]) {//"line[0]"就是每一个线段的开始值 heap.poll(); } heap.add(line[1]);//"line[1]"就是每一个线段的结束值 max = Math.max(max, heap.size()); } return max; } public static class Line { int start; int end; public Line(int s, int e) { start = s; end = e; } } /** * for test * 生成随机的线段,即线段的开始数值,和结尾数值都是随机的,并且开头小于结尾。 * * @param N 要生成多少条随机线段 * @param L 当前生成的线段的开头数值 * @param R 当前生成的线段的结尾数值 * @return 生成的随机的N条记录。二维数组类型。 */ public static int[][] generateLines(int N, int L, int R) { int size = (int) (Math.random() * N) + 1; int[][] ans = new int[size][2]; for (int i = 0; i < size; i++) { int a = L + (int) (Math.random() * (R - L + 1)); int b = L + (int) (Math.random() * (R - L + 1)); if (a == b) { b = a + 1; } ans[i][0] = Math.min(a, b); ans[i][1] = Math.max(a, b); } return ans; } //自定义比较器 //按照每个元素的开始值start升序。 private static class StartComparator implements Comparator<Line> { @Override public int compare(Line o1, Line o2) { return o1.start - o2.start; } } public static void main(String[] args) { Line line1 = new Line(2, 8); Line line2 = new Line(6, 8); Line line3 = new Line(6, 9); Line line4 = new Line(4, 5); Line line5 = new Line(2, 6); Line line6 = new Line(3, 7); //简单测试,定义一个优先级队列,在构造方法中传入自定义比较器。 //那么在heap添加line元素的数据,就是按照line的开始值start,进行升序排序并保存的。 //当然,在heap.poll()的时候,获取line元素,就是start最小的line元素。 PriorityQueue<Line> heap = new PriorityQueue<>(new StartComparator()); heap.add(line1); heap.add(line2); heap.add(line3); heap.add(line4); heap.add(line5); heap.add(line6); while (!heap.isEmpty()) { Line poll = heap.poll(); System.out.println(poll.start + ", " + poll.end); } System.out.println("======================"); int testTimes = 1; int N = 100; int L = 0; int R = 100; System.out.println("test start!"); for (int i = 0; i < testTimes; i++) { int[][] lines = generateLines(N, L, R); System.out.println("lines = " + Arrays.deepToString(lines)); //lines = [[72, 82], [51, 75], [0, 83], [9, 97], [30, 90], [45, 58], [26, 58], [48, 98], [57, 86], [30, 62], [69, 84], [16, 66], [20, 78], [65, 95], [6, 37], [42, 87], [22, 89], [11, 14], [55, 71]] int ans1 = CoverMax1(lines); int ans2 = CoverMax2(lines); int ans3 = CoverMax3(lines); System.out.println("ans1 = " + ans1); System.out.println("ans2 = " + ans2); System.out.println("ans3 = " + ans3); if (ans1 != ans2 || ans1 != ans3) { System.out.println("Oops!"); } } System.out.println("test end!"); } }
标签:方式,int,线段,lines,重合,heap,new,Line From: https://www.cnblogs.com/TheFloorIsNotTooHot/p/17019156.html