代码随想录算法训练营第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(si - 11, si1),选取前一个区间和本区间的最小右边界作为当前区间的右边界。这也就相当于将那一个有边界更大的区间删除掉了然后两区间组成了一个新的区间。我觉得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;
    }
};
相关推荐
江畔柳前堤1 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore2 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考4 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX5 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面5 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号6 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽6 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI6 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者8 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者8 小时前
【征程6】校准量化中HistogramObserver解析
算法