代码随想录算法训练营 Day 30 | 435.无重叠区间,763.划分字母区间,56.合并区间

文章介绍了几种处理区间问题的算法,包括435.无重叠区间,通过排序和遍历去除重叠;763.划分字母区间,使用贪心策略按字符出现最远下标划分;56.合并区间,对重叠区间进行合并。这些方法都涉及到了排序、区间比较和状态更新。
摘要由CSDN通过智能技术生成

435.无重叠区间

讲解链接:代码随想录-435.无重叠区间

​​

首先根据子数组的左边数字排序,然后从 1 开始循环变遍历,如果当前做边界小于前一个数组的右边界,说明这两个数组有重叠,移除数量加 1。注意:此时可能需要更新当前数组的右边界,如果当前数组右边界大于前一个数组右边界,则取前一个数组右边界;因为我们要移除最小数量,所以默认把大的移除,小的保留,以便给下一个数组比较时,就可以保证最少数量。

比如下面这张图,需要移除 2,3,5 数组即可。在出现重叠的时候,右边界值取最小的。

 

public int eraseOverlapIntervals(int[][] intervals) {
    Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
    int result = 0;
    for (int i = 1; i < intervals.length; i++) {
        if (intervals[i][0] < intervals[i - 1][1]) {
            result++;
            intervals[i][1] = Math.min(intervals[i][1], intervals[i - 1][1]);
        }
    }
    return result;
}

763.划分字母区间

讲解链接:代码随想录-763.划分字母区间

贪心?

因为都是小写字母,所以我们可以创建一个长度 26 的数组,否则可以使用 Map。我们遍历字符串,用字母的 ASCII 值当数组下标,值存放字符串中的下标。因为是顺序遍历,如果字符串中有相同字符,就会记录这个字符的最远下标。

得到数组后,我们创建结果集、一个左边界和右边界,再次遍历字符串,那当前的遍历的字母到之前创建数组中保存的最远下标,更新右边界为最大值,如果遍历到了最大值,就说明可以分割一次了。在添加结果的时候注意边界问题,right - left +1​ 。left = i + 1​ 。

 

public List<Integer> partitionLabels(String s) {
    int[] hash = new int[26];
    for (int i = 0; i < s.length(); i++) {
        hash[s.charAt(i) - 'a'] = i;
    }
    List<Integer> result = new ArrayList<>();
    int left = 0;
    int right = 0;
    for (int i = 0; i < s.length(); i++) {
        right = Math.max(hash[s.charAt(i) - 'a'], right);
        if (i == right) {
            result.add(right - left + 1);
            left = i + 1;
        }
    }
    return result;
}

暴力破解

思路:使用二维集合存储子字符串,主要利用集合的 contains 来判断子集合是否存在当前轮询到的字符串,如果存在则把这个子集合后面的集合全部添加进来并删除,如果不存在就新建一个子数组来保存。

public List<Integer> partitionLabels(String s) {
    List<List<Character>> list = new ArrayList<>();
    for (int i = 0; i < s.length(); i++) {
        Character c = s.charAt(i);
        boolean contains = false;
        for (int j = 0; j < list.size(); j++) {
            List<Character> subList = list.get(j);
            if (subList.contains(c)) {
                for (int k = j + 1; k < list.size(); k++) {
                    subList.addAll(list.get(k));
                }
                for (int k = list.size() - 1; k > j; k--) {
                    list.remove(k);
                }
                subList.add(c);
                contains = true;
                break;
            }
        }
        if (contains) {
            continue;
        }
        List<Character> subList = new ArrayList<>();
        subList.add(c);
        list.add(subList);
    }
    return list.stream().map(a -> a.size()).collect(Collectors.toList());
}

56.合并区间

讲解链接:代码随想录-56.合并区间

跟之前的题目类似,重叠则更新区间,否则就添加到结果中,注意在循环外要主动添加最后一个数组。

public int[][] merge(int[][] intervals) {
    // 按照左边界排序
    Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
    List<int[]> results = new ArrayList<>();

    for (int i = 1; i < intervals.length; i++) {
        // 如果当前数组跟前一个数组有重叠,则更新当前数组的左边界和右边界
        if (intervals[i][0] <= intervals[i - 1][1]) {
            intervals[i][0] = Math.min(intervals[i][0], intervals[i - 1][0]);
            intervals[i][1] = Math.max(intervals[i][1], intervals[i - 1][1]);
        } else {
            // 没有重叠时就可以保存前一个数组,因为我们一直在更新,所以可以直接保存。
            results.add(intervals[i - 1]);
        }
    }
    // 注意这里要在保存一次最后的数组,因为我们在循环中一直保存的是前一个符合数组。
    results.add(intervals[intervals.length - 1]);

    return results.toArray(new int[results.size()][]);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值