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

LeetCode 435 无重叠区间

题目链接:https://leetcode.cn/problems/non-overlapping-intervals/

思路:

我采用的思路和昨天的射箭题类似,在左边界进行排序。如果存在重叠区间,那么就记录下来,并且更新右边界

代码:

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int result = 0;
        if(intervals.size()==0||intervals.size()==1) return result;
        sort(intervals.begin(),intervals.end(),cmp);
        for(int i = 1;i<intervals.size();i++)
        {
            if(intervals[i][0]>=intervals[i-1][1])
                continue;
            else
            {
                intervals[i][1] = min(intervals[i][1],intervals[i-1][1]);
                result++;
            }
        }
        return result;
    }

    static bool cmp(const vector<int>&a,const vector<int>&b)
    {
        if(a[0]==b[0])
            return a[1]<b[1];

        return a[0]<b[0];
    }

};

总结

相对简单

LeetCode 763 划分字母区间

题目链接:https://leetcode.cn/problems/partition-labels/

思路:

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

可以分为如下两步:

  • 统计每一个字符最后出现的位置

  • 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点

代码:

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;

        // 通过每个字母的最远下标划分区间
        int left = 0;
        int right = 0;
        vector<int>result;
        for(int i = 0;i<s.size();i++)
        {
            right = max(right,hash[s[i]-'a']);
            if(i==right)    // 说明此时已经遍历到了最远处,i前面的元素都只会在该区间内出现
            {
                result.push_back(right-left+1);
                left = i+1; // 更新区间的起点,终点会自动在下一个循环中更新
            }
        }
        return result;

    }
};

总结

第一次遇到这种题目,一开始有点懵,听完讲解之后豁然开朗。

LeetCode 56 合并区间

题目链接:https://leetcode.cn/problems/merge-intervals/

思路:

重叠区间的题目,自己的想法是按左边界排序。

如果发现重叠,那么就同时更新左边界和右边界。这样操作的话,相对复杂。卡哥的思路是排序好了之后将第一个数组放入结果集后,比较后面数组的左边界和第一个数组的右边界。如果左边界小于右边界,那么必然重叠,此时只需要更新结果集里元素的右边界即可。

代码:

  • 自写

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>>result;
        if(intervals.size()==1) return intervals;
        sort(intervals.begin(),intervals.end(),cmp);
        for(int i =1;i<intervals.size();i++)
        {
            if(intervals[i][0]>intervals[i-1][1])
                result.push_back(intervals[i-1]);
            else
            {
                intervals[i][0] = min(intervals[i-1][0],intervals[i][0]);
                intervals[i][1] = max(intervals[i-1][1],intervals[i][1]);
            }
            if(i==intervals.size()-1)
                result.push_back(intervals[i]);
        }
        return result;
    }

    static bool cmp(const vector<int>&a,const vector<int>&b)
    {
        if(a[0]==b[0])
            return a[1]<b[1];
        return a[0]<b[0];
    }

};
  • 优化代码

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>>result;
        if(intervals.size()==1) return intervals;
        sort(intervals.begin(),intervals.end(),cmp);
        // 第一个区间就可以放进结果集里,后面如果重叠,在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;
    }

    static bool cmp(const vector<int>&a,const vector<int>&b)
    {
        if(a[0]==b[0])
            return a[1]<b[1];
        return a[0]<b[0];
    }
};

总结

相对简单。

今日总结:

今天就划分字母区间如何找分割点没有想到,其余题目相对简单。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值