【算法训练 day38 无重叠区间、长度最小的子数组、合并区间】


一、无重叠区间-LeetCode 435

Leecode链接: leetcode 435
文章链接: 代码随想录
视频链接: B站

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

示例:

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

思路

区域重叠问题,按照数组首元素进行排序,然后判断是否有区域重叠,如果有一个重叠,res自加1。

实现代码

1.双指针

//cpp
class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if(intervals.size() == 0) return 0;
        sort(intervals.begin(),intervals.end(),[](const vector<int>& a,const vector<int>& b){ 
            return a[0]<b[0];});

        int res = 0;

        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]);
                res++;
            }
            
        }
        return res;
    }
};

个人问题

无。

总结

判断是否重叠只需要在排序后,判断前一个数组的末尾元素是否严格大于后一个数组开头元素就行。


二、划分字母区间-LeetCode 763

Leecode链接: LeetCode 763
文章链接: 代码随想录
视频链接: B站

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

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

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

示例:

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

思路

划分成一个字段的依据是,每个字段中元素不会在其他字段出现,这就意味着如果是一个字段那么字段中字符的分布区间都是相互重叠的,否则不是一个字段。记录每个字母最后一次出现的位置,然后循环判断当前i是否为当前字段中某个元素的最远坐标,是的话就将结果插入res中。

实现代码

快慢指针(滑动窗口)

//cpp
class Solution {
public:
    vector<int> partitionLabels(string s) {
        int hash[27] = {0};
        for(int i = 0;i<s.size();i++){
            hash[s[i] - 'a'] = i;
        }

        vector<int> res;
        int right = 0;
        int left = 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;
    }
};

个人问题

想法是一致的,但是在记录每个元素出现的最远坐标使用的是vector<vector>来记录,这就需要三次for循环,感觉可能超时,个人代码没有实现。

总结

题目本质还是判断是否有重叠区间,但最终代码思路更为简洁。


三.合并区间-LeeCode 56

Leecode链接: LeetCode 56
文章链接: 代码随想录
视频链接: B站

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

示例:

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

思路

先对数组进行排序,如果两个数组重叠,然后将两个区间之间右区间稍大的值进行更新,表示合并操作。没有重叠就直接插入该数组。

实现代码

个人代码

//cpp
class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end(),[](const vector<int>& a,const vector<int>& b){
            return a[0]<b[0];
        });

        vector<int> temp = {intervals[0][0],0};
        vector<vector<int>> res;
        int i = 1;
        for(i;i<intervals.size();i++){
            if(intervals[i][0]<=intervals[i-1][1]){
                intervals[i][1] = max(intervals[i-1][1],intervals[i][1]);
            }
            else{
                temp[1] = intervals[i-1][1];
                res.push_back(temp);
                temp[0] = intervals[i][0];
            }
        }
        temp[1] = intervals[i-1][1];
        res.push_back(temp);
        return res;
    }
};

简介代码

//cpp
class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> result;
        if (intervals.size() == 0) return result; // 区间集合为空直接返回
        // 排序的参数使用了lambda表达式
        sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});

        // 第一个区间就可以放进结果集里,后面如果重叠,在result上直接合并
        result.push_back(intervals[0]); 

        for (int i = 1; i < intervals.size(); i++) {
            if (result.back()[1] >= intervals[i][0]) { // 发现重叠区间
                // 合并区间,只更新右边界就好,因为result.back()的左边界一定是最小值,因为我们按照左边界排序的
                result.back()[1] = max(result.back()[1], intervals[i][1]); 
            } else {
                result.push_back(intervals[i]); // 区间不重叠 
            }
        }
        return result;
    }
};

个人问题

两个代码思想一致,实现方式有所不同。

总结

个人代码在在数组重叠时,会更新数组右边界,只有在不重叠才会将其插入,这就意味着最后一个数组没有插入到结果中,所以for循环结束后还要进行一次push_back操作,简洁代码则是将第一个数组就插入,然后如果重叠直接更新res中back()位置的右边界,否则插入当前数组,实现上更简便。

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值