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

LeetCode 435. 无重叠区间
LeetCode 763.划分字母区间
LeetCode 56. 合并区间

无重叠区间

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。

用最少数量的箭引爆气球很像,唯一的区别是引爆气球记录的是非重叠数量, 本题记录的是重叠数量。 在 if else 内操作会有所不同。

另外,本题对左区间和右区间均可排序,可以计算非重叠数量,用总数量减去非重叠得到重叠数量,也可以按下面代码直接计算重叠数量。

class Solution {
   
    // [1,2],[2,3],[3,4],[1,3]
    // [1,2],[1,3],[2,3],[3,4]  => [1,2],[1,2],[2,3],[3,4]
    // 1 < 2 重叠 记录删除 result++
    // 重叠记录最小右区间 
    // 直到遍历完数组
    public int eraseOverlapIntervals(int[][] intervals) {
   
        Arrays.sort(intervals, (a, b) -> {
   
            if (a[0] == b[0]) return a[1] - b[1];
            return a[0] - b[0];
        });

        int result = 0;

        for (int i = 1; i < intervals.length; i++) {
   
            if (intervals[i][0] < intervals[i - 1][1]) {
     // 重叠步骤
                intervals[i][1] = Math.min(intervals[i][1], intervals[i - 1][1]); 
                result++;   
            } 
        }
        return result;
    }
}

划分字母区间

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

题目要求同一字母最多出现在一个片段中。

在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界(Math.max()),说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。

  • 统计每一个字符最后出现的位置
  • 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点
class Solution {
   
    public List<Integer> partitionLabels(String s) {
   
        List<Integer> result = new ArrayList<>();

        int[] hash = new int[26];

        for (int i = 0; i < s.length(); i++) {
   
            char c = s.charAt(i);
            hash[c - 'a'] = i;
        }

        // s -> [8, 5, 8, ... ]

        int idx = 0;
        int last = -1;
        for (int i = 0; i < s.length(); i++) {
   
            char c = s.charAt(i);
            idx = Math.max(idx, hash[c - 'a']);
            if (i == idx) {
   
                result.add(i - last);
                last = i;
            }
        }
        return result;
    }
}
class Solution {
   

    public int[][] findPartitions(String s) {
   
        // "ababcbacadefegdehijhklij"
        List<Integer> temp = new ArrayList<>();
        int[][] hash = new int[26][2]; // 26 个字母 2 列 表示该字母对应的区间

        // 哈希数组
        // [[0,8], [1,5], [4,7], [9,14], [10, 15] ...]
        for (int i = 0; i < s.length(); i++) {
   
            char c = s.charAt(i);
            if (hash[c - 'a'][0] == 0) hash[c - 'a'][0] = i;
            hash[c - 'a'][1] = i;
            hash[s.charAt(0) - 'a'][0] = 0; 
        }

        List<List<Integer>> h = new LinkedList<>();
        // 去除字符串中未出现的字母所占用区间
        // 组装区间到集合
        for (int i = 0; i < 26; i++) {
   
            // if (hash[i][0] != hash[i][1]) {
   
                temp.clear();
                temp.add(hash[i][0]);
                temp.add(hash[i][1]);
                h.add(new ArrayList<>(temp));
            // }
        }

        // 存入数组
        int[][] res = new int[h.size()][2];
        for (int i = 0; i < h.size(); i++) {
   
            List<Integer> list = h.get(i);
            res[i][0] = list.get(0);
            res[i][1] = list.get(1);
        }
        return res;
    }

    public List<Integer> partitionLabels(String s) {
   
        int[][] partitions = findPartitions(s);
        List<Integer> result = new ArrayList<>();
        // [[0,8], [1,5], [4,7], [9,14], [10, 15] ...]
        Arrays.sort(partitions, (o1, o2) -> Integer.compare(o1[0], o2[0]));
        int right = partitions[0][1];
        int left = 0;
        for (int i = 0; i < partitions.length; i++) {
   
            if (partitions[i][0] > right) {
    // 一旦下一区间左边界大于当前右边界,即可认为出现分割点
                result.add(right - left + 1);
                left = partitions[i][0];
            }
            right = Math.max(right, partitions[i][1]);
        }
        result.add(right - left + 1);
        return result;
    }
}

合并区间

这几道题都是判断区间重叠,区别就是判断区间重叠后的逻辑,本题是判断区间重贴后要进行区间合并。

所以一样的套路,先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同。

在这里插入图片描述

class Solution {
   
    public int[][] merge(int[][] intervals) {
   
        Arrays.sort(intervals, (o1, o2) -> Integer.compare(o1[0], o2[0]));

        List<int[]> res = new ArrayList<>();

        int start = intervals[0][0];
        // int rightMaxBound = intervals[0][1];

        for (int i = 1; i < intervals.length; i++) {
   
            // if (intervals[i][0] > rightMaxBound) {
   
            if (intervals[i][0] > intervals[i - 1][1]){
   
                res.add(new int[]{
   start, intervals[i - 1][1]});
                // res.add(new int[]{start, rightMaxBound});
                start = intervals[i][0];
                // rightMaxBound = intervals[i][1];
            } else{
   
                // rightMaxBound = Math.max(rightMaxBound, intervals[i][1]);
                intervals[i][1] = Math.max(intervals[i][1], intervals[i - 1][1]);
            }
        }
        // res.add(new int[]{start, rightMaxBound});
        res.add(new int[]{
   start, intervals[intervals.length - 1][1]});
        return res.toArray(new int[res.size()][]);
    }
}

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-20 23:20:04       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-20 23:20:04       106 阅读
  3. 在Django里面运行非项目文件

    2024-02-20 23:20:04       87 阅读
  4. Python语言-面向对象

    2024-02-20 23:20:04       96 阅读

热门阅读

  1. 软考笔记--信息系统开发方法(上)

    2024-02-20 23:20:04       48 阅读
  2. CES 的Agent插件状态显示“故障”该如何处理?

    2024-02-20 23:20:04       55 阅读
  3. 游戏分组/王者荣耀

    2024-02-20 23:20:04       44 阅读
  4. 关于游戏开发的那些工具

    2024-02-20 23:20:04       49 阅读
  5. 15个学习Go语言的网站推荐

    2024-02-20 23:20:04       44 阅读
  6. 最优字符串分隔符:零宽度空格和字符

    2024-02-20 23:20:04       47 阅读
  7. 计算机网络第三章问答题

    2024-02-20 23:20:04       46 阅读