首页 > 其他分享 >最大线段重合问题(堆实现的方式)

最大线段重合问题(堆实现的方式)

时间:2023-01-01 22:34:10浏览次数:39  
标签:方式 int 线段 lines 重合 heap new Line

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

相关文章