算法修炼Day36|● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

55 阅读1分钟

LeetCode:435. 无重叠区间 - 力扣(LeetCode)

1.思路

将重叠区间进行排序,Java8新特性,定义一个计数器和数据段的前驱有边界,将当前元素左边界与前驱节点右边界进行比较。如果当前节点左边界小于前驱线段右边界,说明两者之间有交叉,计数器+1,更新pre为两者的较小值(相当于删除了右边界较大的值)。而如果当前节点的左边界大于等于前驱线段的右边界,则更新pre为当前节点的右边界,依次循环进行。

2.代码实现
class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        // 排序
        Arrays.sort(intervals, (a, b) -> {
            return Integer.compare(a[0], b[0]);
        });
        // 计数器,移除的最小数量
        int count = 0;
        // 移除右侧区间较远的那个
        int pre = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] < pre) {
                count++;
                pre = Math.min(pre, intervals[i][1]); // 更新pre为两者之间的较小值,相当于删除了较大值
            } else {
                pre = intervals[i][1]; // 更新pre
            }
        }
        return count;
    }
}
3.复杂度分析

时间复杂度:O(n).

空间复杂度:O(1).

LeetCode:

1.思路

遍历更新获取字符串中每个字符出现的最远位置,遍历更新获取子串左右位置,获取相应的子串长度加入结果集中。

2.代码实现
class Solution {
    public List<Integer> partitionLabels(String s) {
        // 结果集
        List<Integer> result = new LinkedList<>();
        // 26个英文字母输入???
        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 (i == right) {
                result.add(i - left + 1); 
                left = i + 1; // 更新左边界
            }
        }
        return result;
    }
}
3.复杂度分析

时间复杂度:O(nlogn).

空间复杂度:O(n).

LeetCode:class Solution {

public int[][] merge(int[][] intervals) {
    // 结果集
    List<int[]> result = new ArrayList<>();
    // 对区间进行排序
    Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
    // 前驱节点
    int preLeft = intervals[0][0];
    int preRight = intervals[0][1];
    for (int i = 1; i < intervals.length; i++) {
        if (intervals[i][0] <= preRight) { // 如果有重叠区间,更新有边界为两者之间的较大值
            preRight = Math.max(preRight, intervals[i][1]);
        } else { 
            // 当前索引左侧值大于前一线段右侧值,无重叠区间,直接加入结果集
            result.add(new int[]{preLeft, preRight});
            preLeft = intervals[i][0];
            preRight = intervals[i][1];
        }
    }
    // 将最后一段加入到结果集
    result.add(new int[]{preLeft, preRight});
    // 将结果集转化为数组
    return result.toArray(new int[result.size()][]);
}

}

1.思路

创建结果集收集无重叠数组,对区间进行左边界排序,设定前驱左右节点值,对数组进行遍历(更新前驱数组左右边界值)当前数组左值大于前一数组右值时,说明无重叠加入结果集,当前数组左值小于等于前一数组右值时,有重叠,更新数组右边界为两者之间的较大值。记得将最后一段数组加入结果集中,将结果集转为二维数组返回即可。

2.代码实现
class Solution {
    public int[][] merge(int[][] intervals) {
        // 结果集
        List<int[]> result = new ArrayList<>();
        // 对区间进行排序
        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
        // 前驱节点
        int preLeft = intervals[0][0];
        int preRight = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] <= preRight) { // 如果有重叠区间,更新有边界为两者之间的较大值
                preRight = Math.max(preRight, intervals[i][1]);
            } else { 
                // 当前索引左侧值大于前一线段右侧值,无重叠区间,直接加入结果集
                result.add(new int[]{preLeft, preRight});
                preLeft = intervals[i][0];
                preRight = intervals[i][1];
            }
        }
        // 将最后一段加入到结果集
        result.add(new int[]{preLeft, preRight});
        // 将结果集转化为数组
        return result.toArray(new int[result.size()][]);
    }
}
3.复杂度分析

时间复杂度:O(nlogn).排序需要的时间开销

空间复杂度:O(logn).// 排序需要的空间开销