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

Leetcode - 435:无重叠子区间

题目:

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

示例 1:

复制代码
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

复制代码
输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

复制代码
输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

笔记:

这道题删除重叠区间的最小值:我们可以想象为当我们遍历到了一个重叠的区间之后,我们会将当前区间的右边界会改变为min(s[i - 1][1], s[i][1]),选取前一个区间和本区间的最小右边界作为当前区间的右边界。这也就相当于将那一个有边界更大的区间删除掉了然后两区间组成了一个新的区间。我觉得1这么做就可以不管头怎么样只需要控制区间尾即可。

之前有一处我想不明白的点就是这个题解释如何实现最小的重叠区见这个要求的呢?当存在三个连续的区间的时候。如果其中一个区间与另两个区间都有重叠,但其余两个区间互不重叠,这时候最小的策略就是去掉重叠最多的哪个区间保留剩余两个区间。我认为这个局部优先策略是:将所有区间进行一一排序之后我们便开始判断相邻两个区间是否发生重叠如果发生重叠那么我们就讲这两个区间中跨度较大的区间删除掉(可以这么理解),这样后面的区间变最大化的减少了与前面区间的重合概率。

cpp 复制代码
class Solution {
public:
    static bool abs(vector<int>& a, vector<int>& b){
        return a[0] < b[0];
    }
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int count = 0;
        sort(intervals.begin(), intervals.end(), abs);
        for(int i = 1; i < intervals.size(); i++){
            if(intervals[i][0] < intervals[i - 1][1]){
                intervals[i][1] = min(intervals[i - 1][1], intervals[i][1]);
                count++;
            }
        }
        return count;
    }
};

Leetcode - 763:划分字母区间

题目:

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s

返回一个表示每个字符串片段的长度的列表。

示例 1:

复制代码
输入:s = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。 

示例 2:

复制代码
输入:s = "eccbbbbdec"
输出:[10]

笔记:

这道题初看是一头雾水的,因为不知道这个尽可能多是怎么取得的:

这道题的答题思路是利用哈希表不断更新每个字符出现的最后的位置,然后再次遍历该字符串当遍历到了前面区间内出现位置最远的字符时便加入到结果数组再讲left + 1控制区间。总的来说是利用哈希表来更新每个字符最远出现的位置,利用双指针控制区间的范围并将该子串加入到结果数组。

cpp 复制代码
class Solution {
public:
    vector<int> partitionLabels(string s) {
        vector<int> hash(26, 0);
        vector<int> res;
        for(int i = 0; i < s.size(); i++){
            hash[s[i] - 'a'] = i;
        }
        int left = 0;
        int right = 0;
        for(int i = 0; i < s.size(); i++){
            right = max(right, hash[s[i] - 'a']);
            if(i == right){
                res.push_back(right - left + 1);
                left = i + 1;
            }
        }
        return res;
    }
};

巧妙的地方在于利用了哈希表来存储每个字符互出现的最远位置,利用双指针记录每一个最大区间。

Leetcode - 56:合并区间

题目:

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间

示例 1:

复制代码
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

复制代码
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

笔记:

这道题刚看起来感觉有点头绪,就是将之前修改区间右边界的min改为max,再讲该区间的左右边界加入到结果数组中。但是我在记录结果的时候就犯了难,我认为是需要用到while来处理的,因为这里的right肯呢个是在不断更新的,如果没找到一次right就加入数组就不是最终结果了,这里对于left的更新是当遇到了不重叠的数组是我们就将left + 1处理。

但这道题还是可以用双指针的解法来解决的,就只需要注意最后一个区间最后别忘了要加入到结果集中:

cpp 复制代码
#include <vector>
#include <algorithm>

using namespace std;

class Solution {
public:
    static bool compare(vector<int>& a, vector<int>& b) {
        return a[0] < b[0]; // 按照区间的左端点升序排序
    }

    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if (intervals.empty()) return {}; // 如果区间为空,直接返回空数组
        sort(intervals.begin(), intervals.end(), compare); // 按照左端点升序排序

        vector<vector<int>> res;
        int left = intervals[0][0];
        int right = intervals[0][1];
        
        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i][0] <= right) { // 当前区间与上一个区间有重叠
                right = max(right, intervals[i][1]); // 更新右端点为两个区间的最大值
            } else { // 当前区间与上一个区间没有重叠
                res.push_back({left, right}); // 将合并后的区间加入结果集
                left = intervals[i][0]; // 更新左端点为当前区间的左端点
                right = intervals[i][1]; // 更新右端点为当前区间的右端点
            }
        }
        res.push_back({left, right}); // 加入最后一个合并后的区间
        return res;
    }
};

自己debug的版本:

cpp 复制代码
class Solution {
public:
    static bool abs(vector<int>& a, vector<int>& b){
        return a[0] < b[0];
    }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> res;
        sort(intervals.begin(), intervals.end(), abs);
        int left = 0;
        int right = 0;
        for(int i = 1; i < intervals.size(); i++){
            if(intervals[i - 1][1] >= intervals[i][0]){
                intervals[i][1] = max(intervals[i - 1][1], intervals[i][1]);
                right = i;
            }else{
                res.push_back({intervals[left][0], intervals[right][1]});
                left = i;
                right = i;
            }
        }
        res.push_back({intervals[left][0], intervals[right][1]});
        return res;
    }
};
相关推荐
秋夫人18 分钟前
B+树(B+TREE)索引
数据结构·算法
梦想科研社1 小时前
【无人机设计与控制】四旋翼无人机俯仰姿态保持模糊PID控制(带说明报告)
开发语言·算法·数学建模·matlab·无人机
Milo_K1 小时前
今日 leetCode 15.三数之和
算法·leetcode
Darling_001 小时前
LeetCode_sql_day28(1767.寻找没有被执行的任务对)
sql·算法·leetcode
AlexMercer10121 小时前
【C++】二、数据类型 (同C)
c语言·开发语言·数据结构·c++·笔记·算法
Greyplayground1 小时前
【算法基础实验】图论-BellmanFord最短路径
算法·图论·最短路径
蓑 羽1 小时前
力扣438 找到字符串中所有字母异位词 Java版本
java·算法·leetcode
源代码:趴菜1 小时前
LeetCode63:不同路径II
算法·leetcode·职场和发展
儿创社ErChaungClub1 小时前
解锁编程新境界:GitHub Copilot 让效率翻倍
人工智能·算法
前端西瓜哥1 小时前
贝塞尔曲线算法:求贝塞尔曲线和直线的交点
前端·算法