代码随想录算法训练营第三十六天|435. 无重叠区间、763.划分字母区间、56. 合并区间

目录

435. 无重叠区间

763.划分字母区间

 56. 合并区间 


今天的三道题目,都算是 重叠区间 问题,大家可以好好感受一下。 都属于那种看起来好复杂,但一看贪心解法,惊呼:这么巧妙! 还是属于那种,做过了也就会了,没做过就很难想出来。不过大家把如下三题做了之后, 重叠区间 基本上差不多了

435. 无重叠区间

代码随想录

题解思路:

本题和射爆气球的最小弓箭数量的思路一致,需要先把数组按从小到大排列,然后再判断,需要注意以下两点:
1、只有当前一个数组元素的右边界大于当前数组元素的左边界,说明两个数组一定重叠,此时才对结果result做++操作
2、还需要判断与下面的区间是否重叠,因此需要重新更新下数组元素的右边界,为了使得移除区间的数量最小,因此需要更新为当前重叠区间右边界的最小值!!!这点很重要也很容易忽略

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals, (a,b)-> {
            if(a[0] == b[0]) Integer.compare(a[1], b[1]);
            return Integer.compare(a[0], b[0]);
        }); //如果元素数组的第一个元素相同,按照第二个元素从小到大排列;如果不相同,则按照第一个元素的值从小到大排列
        int result = 0;
        for(int i = 1; i < intervals.length; i++){
            if(intervals[i - 1][1] > intervals[i][0]){ //只有当前一个数组元素的右边界大于当前数组元素的左边界,说明两个数组一定重叠,但是还需要判断与下面的区间是否重叠,因此需要重新更新下数组元素的右边界,为了使得移除区间的数量最小,因此需要更新为当前重叠区间右边界的最小值!!!这点很重要也很容易忽略
                result++;
                intervals[i][1] = Math.min(intervals[i-1][1],intervals[i][1]);
            }
        }
        return result;
    }
}

763.划分字母区间

代码随想录

题解思路:

本题主要分两步走:
第一步:记录每个元素出现的最远位置,由于后面出现相同字母的下标值会不断的覆盖前面记录的下标值,因此遍历结束后,对应字母处的元素值记录的就是该字母出现的最远位置;
第二步:第二次遍历整个字符串,获取切割字符串片段的长度时,需要不断更新右边界,直到遍历片段中同一个字母出现的最大位置,一旦遍历到该最大位置就理解记录,从而保证可以尽可能的划分多个片段。

class Solution {
    public List<Integer> partitionLabels(String s) {
        int[] hashSet = new int[26];
        for(int i = 0; i < s.length(); i ++){
            hashSet[s.charAt(i) - 'a'] = i; //第一步:记录每个元素出现的最远位置,由于后面出现相同字母的下标值会不断的覆盖前面记录的下标值,因此遍历结束后,对应字母处的元素值记录的就是该字母出现的最远位置
        }

        List<Integer> result = new ArrayList<>(); //存放结果数组
        int left = 0, right = 0; //使用双指针,记录切割字符串区间片段的起始和终止位置
        for(int i = 0; i < s.length(); i++){
            right = Math.max(hashSet[s.charAt(i) - 'a'], right);//不断更新右边界,直到遍历片段中同一个字母出现的最大位置,一旦遍历到该最大位置就理解记录,从而保证可以尽可能的划分多个片段
            if(i == right){
                result.add(right-left+1); //记录对应片段的字符串个数
                left = i + 1;
            }
        }
        return result;
    }
}

 56. 合并区间 

本题相对来说就比较难了。

代码随想录

题解思路:

和之前的重叠区间处理的逻辑一致,唯一写卡住的就是如何把第一个数组元素存入到结果集中,这里比较巧妙的处理方式是直接把第一个数组元素存入到结果集中,处理重叠区间的时候一般都是从第二个数组元素开始遍历,那么这里是直接取出结果集中最后一个数组元素,然后直接修改结果集中最后一个数组元素,进行合并后的区间(如果可以合并的话),其实也就等价于上一个数组的右边界和当前数组的左边界进行比较,如果上一个数组右边界大于等于当前数组的左边界,因此(如果可以合并的话)也省略了再次重复添加的过程!!!

class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (a,b) -> {
            if(a[0] == b[0]) return Integer.compare(a[1], b[1]);
            return Integer.compare(a[0],b[0]);
        });

        LinkedList<int[]> result = new LinkedList<>();
        result.addLast(intervals[0]);  //结果集中至少有个一个数组元素,就是数组中的第一个数组元素

        //直接取出结果集中最后一个数组元素,然后修改该数组合并后的区间(如果可以合并的话),其实也就等价于上一个数组的右边界和当前数组的左边界进行比较,如果上一个数组右边界大于等于当前数组的左边界,那么进行下面的区间合并操作
        for(int i = 1; i < intervals.length; i++){
            if(result.getLast()[1] >= intervals[i][0]){ 
                intervals[i][0] = Math.min(result.getLast()[0], intervals[i][0]);  //这行没必要使用min()函数,因为数组元素就是按照左边界进行从小到大排序,所有存入到结果集中的数组如果两个区间可以合并,那么左边界一定是这两个区间左边界的最小值
                intervals[i][1] = Math.max(result.getLast()[1], intervals[i][1]); //由于数组是按照按照左边界进行从小到大排序,因为对于两个区间的右边界是不确定谁大谁小的,所有要使用max()函数进行比较取值,更新最大的右边界即可
                result.removeLast();
                result.addLast(new int[]{intervals[i][0], intervals[i][1]});
            }else{
                result.add(intervals[i]);
            }
        }
        return result.toArray(new int[result.size()][]);
    }
}

猜你喜欢

转载自blog.csdn.net/tore007/article/details/130970687