【代码训练营】day35 | 435. 无重叠区间 & 763.划分字母区间 & 56. 合并区间

所用代码 java

无重叠区间 LeetCode 435

题目链接:无重叠区间 LeetCode 435 - 中等

思路

本题和昨天射气球的题一模一样。

贪心贪的每次保留最小的右区间,才可以留下最多的区间。

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        // 需要移除区间的数量
        int count = 0;
        // 按左边界排序
        Arrays.sort(intervals, (o1,o2) -> o1[0] - o2[0]);
        // 从第二个区间开始比较
        for (int i = 1; i < intervals.length; i++) {
            // 后一个区间的左边界大于等于前一个区间的有边界,就没重叠
            if (intervals[i][0] >= intervals[i-1][1]){
                continue;
            }else {
                count++;
                // 有重叠的时候,把最小的右边界保留
                intervals[i][1] = Math.min(intervals[i][1], intervals[i-1][1]);
            }
        }
        return count;
    }
}

总结

我们的核心在于intervals[i][1] = Math.min(intervals[i][1], intervals[i-1][1]);

举例:[1, 10], [2, 3], [4, 5], [6, 7] 这四个区间只用移除 [1,10] 其他的就都不重复了!!

本题还可以按右边界排序,代码也是类似的:

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        // 需要移除区间的数量
        int count = 0;
        // 按右边界排序
        Arrays.sort(intervals, (o1,o2) -> o1[1] - o2[1]);
        // 从第二个区间开始比较
        for (int i = 1; i < intervals.length; i++) {
            // 后一个区间的左边界大于等于前一个区间的右边界,就没重叠
            if (intervals[i][0] >= intervals[i-1][1]){
                continue;
            }else {
                // 贪心:更新最小的右区间
                intervals[i][1] = Math.min(intervals[i][1],intervals[i-1][1]);
                count++;
            }
        }
        return count;
    }
}

划分字母区间 LeetCode 763

题目链接:划分字母区间 LeetCode 763 - 中等

思路

无。


字符只出现在该区间,我们尽可能的分出更多的区间。

class Solution {
    public List<Integer> partitionLabels(String s) {
        List<Integer> result = new LinkedList<>();
        // 记录26个字母出现的最远的下标
        int[] hash = new int[26];
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            hash[chars[i] - 'a'] = i;
        }
        // 记录划分片段的左右端点
        int left = 0;
        int right = 0;
        for (int i = 0; i < chars.length; i++) {
            right = Math.max(right, hash[chars[i] - 'a']);
            if (right == i){
                result.add(right - left + 1);
                left = i + 1; // 下一次起始位置,左端点
            }
        }
        return result;
    }
}

总结

本题思路如图:

在这里插入图片描述

  • 记录每个字母出现的最远位置
  • 在该字母到出现最远位置中,有其他字母的最远位置超过了该字母,更新最远位置
  • 到达最远位置就分为一段。

贪心贪的就是字母的最远位置,每次有更远的就更新,知道到达这最远的地方。

合并区间 LeetCode 56

题目链接:合并区间 LeetCode 56 - 中等

思路

和上面的题一样,但是多了一个合并的操作

class Solution {
    public int[][] merge(int[][] intervals) {
        // 先排序
        Arrays.sort(intervals, (o1, o2) -> o1[0]-o2[0]);
        List<int[]> list = new LinkedList<>();
        // 记录有几个数加入了list
        int count = 0;
        // 先加入第一个数
        list.add(intervals[0]);
        for (int i = 1; i < intervals.length; i++) {
            int left = list.get(count)[0];
            int right = list.get(count)[1];
            if (right >= intervals[i][0]){
                list.remove(count);
                count--;
                left = Math.min(left, intervals[i][0]);
                right = Math.max(right, intervals[i][1]);
                list.add(new int[]{left, right});
            }else {
                list.add(intervals[i]);
            }
            count++;
        }
        return list.toArray(new int[count][]);
    }
}

优化:

  • 题目已经是按左边界排好序了,所以根本不用判断left的大小,只用更新right为最大的值就行了。
  • 不用另外定义一个count来记录list元素的位置,用list自带的getLast()与removeLast()
class Solution {
    public int[][] merge(int[][] intervals) {
        // 先排序
        Arrays.sort(intervals, (o1, o2) -> o1[0]-o2[0]);
        LinkedList<int[]> list = new LinkedList<>();
        // 先加入第一个数
        list.add(intervals[0]);
        for (int i = 1; i < intervals.length; i++) {
            if (list.getLast()[1] >= intervals[i][0]){
                int left = list.getLast()[0];
                int right = Math.max(list.getLast()[1], intervals[i][1]);
                // 由于要合并,需取出最后一个数组
                list.removeLast();
                list.add(new int[]{left, right});
            }else {
                list.add(intervals[i]);
            }
        }
        return list.toArray(new int[list.size()][]);
    }
}

总结

本题和前面几个题是一样的,都是有重叠区间类型的,我觉得主要分为几个不步骤:

  1. 先对区间进行排序,具体怎么排看要求

    类似:Array.sort(arr, (o1,o2) -> o1[0]-o2[0]

  2. 第一个数需不需要提前加入,需要就加入,不需要就直接循环区间,循环的时候从i=1开始

  3. 每次判断完两个比较区间后,更新左边界或者右边界,随后进入下一判断的区间。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值