算法训练第三十六天 | LeetCode 435、763、56区间重叠问题

LeetCode 435 无重叠区间

题目简析:

求需要去掉几个重叠区间以让剩下的区间无重叠

思路分析:

贪心,看到题目首先反应过来了,按照start来排序

Arrays.sort(数组,Comparator.comparingInt(a->a[0]));

这样排完之后,能尽可能多的把重叠区间靠到一起。而我们也不需要真的去掉重叠区间,就用一个变量来记录一下当前最小右极限即可

 而求最小左区间如果不理解,可以看下面这个示例

[[1,12],[6,13],[12,15],[15,16]]

pre==12在与6比较后一定要去掉一个,而若直接替换成13,则后续还会继续去掉一个区间,为此要求一个最小的

    public int eraseOverlapIntervals(int[][] intervals) {
        //升序
        Arrays.sort(intervals, Comparator.comparingInt(a -> a[0]));
        int count = 0;
        //记录最左的右极限,若碰到需要移除的,则记录移除和上一个的最小左区间
        int pre = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if(pre>intervals[i][0]){
                count++;
                //记录最小左区间
                pre = Math.min(pre,intervals[i][1]);
            }else {
                //非重叠,更换最小左区间
                pre = intervals[i][1];
            }
        }
        return count;
    }

LeetCode 763划分字母区间

题目简析:

把一个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表

思路分析:

题目已经说了分割的字符串连接后依然是s,那么很明显不能对原s进行操作,这道题其实说是区间,我自然而然就想到了,找每一段中,字母所能到达的最远位置,类似找最远区间。

如何记录字母所能到达的最远距离呢?在一个for里去操作(这一点是新学的知识点)

edge[chars[i]-'a'] = i;

 记录好最远位置后,接下来的难题就是如何找到分割点

因为找到了某一段中的最远可达距离,那么当循环的i==这个距离后就证明找到了分割点,记录好后从分割点作为起始点再去往后找

    public List<Integer> partitionLabels(String s) {
        //因为同一字母最多出现在一个片段中
        List<Integer> list = new LinkedList<>();
        int []edge = new int[26];
        char[] chars = s.toCharArray();
        //统计每个字符所到达的最远位置
        for (int i = 0; i < chars.length; i++) {
            edge[chars[i]-'a'] = i;
        }
        int left = 0;
        int right = 0;
        //去找当前段能找到的最远位置的字符
        for (int i = 0; i < chars.length; i++) {
            right = Math.max(right,edge[chars[i] - 'a']);
            if(right == i){
                list.add(right-left+1);
                left = i+1;
            }
        }
        return list;
    }

LeetCode 56合并区间

题目简析:

合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间

思路分析:见注释

    public int[][] merge(int[][] intervals) {
        //本题类似435
        List<int[]> list = new LinkedList<>();
        //排序,重叠的靠近---按左极限排
        Arrays.sort(intervals, Comparator.comparingInt(a->a[0]));
        //这次是需要记录最小左极限,最大右极限---初始化为1
        int left = intervals[0][0];
        int right = intervals[0][1];
        //循环中去查找---已经记录了第一个,i从1开始
        for (int i = 1; i < intervals.length; i++) {
            //下一个的左极限大于记录的右极限,无法合并,重新记录,新一轮比较
            if(right<intervals[i][0]){
                list.add(new int[]{left,right});
                //若最后一个位置是独立的则无法继续add了,因此可能要在for后add一次
                left = intervals[i][0];
                right = intervals[i][1];
            }else {
                //右极限大于等于下一左极限,说明重叠,要合并
                right = Math.max(right,intervals[i][1]);
            }
        }
        //最后一个位置还没有比较
        list.add(new int[]{left,right});
        return list.toArray(new int[list.size()][]);
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值