• 代码随想录算法训练营Day36 —— 435. 无重叠区间、763.划分字母区间、56. 合并区间


    435. 无重叠区间

    思路:

    按照左边排序,按照452引爆气球的思路即可,统计重叠区间个数就是最小删除个数, 直接改点就好。

    代码:

    1. //手搓
    2. class Solution {
    3. private:
    4. static bool cmp(const vector<int>& a, const vector<int>& b){
    5. return a[0]0];
    6. }
    7. public:
    8. int eraseOverlapIntervals(vectorint>>& intervals) {
    9. if(intervals.size() == 0) return 0;
    10. sort(intervals.begin(),intervals.end(),cmp);
    11. int result = 0;
    12. for(int i = 1; isize();i++){
    13. if(intervals[i][0]-1][1]){
    14. result++;
    15. intervals[i][1] = min(intervals[i-1][1],intervals[i][1]);
    16. }
    17. }
    18. return result;
    19. }
    20. };
    21. //卡哥代码
    22. class Solution {
    23. public:
    24. static bool cmp (const vector<int>& a, const vector<int>& b) {
    25. return a[0] < b[0]; // 改为左边界排序
    26. }
    27. int eraseOverlapIntervals(vectorint>>& intervals) {
    28. if (intervals.size() == 0) return 0;
    29. sort(intervals.begin(), intervals.end(), cmp);
    30. int count = 0; // 注意这里从0开始,因为是记录重叠区间
    31. int end = intervals[0][1]; // 记录区间分割点
    32. for (int i = 1; i < intervals.size(); i++) {
    33. if (intervals[i][0] >= end) end = intervals[i][1]; // 无重叠的情况
    34. else { // 重叠情况
    35. end = min(end, intervals[i][1]);
    36. count++;
    37. }
    38. }
    39. return count;
    40. }
    41. };
    • 时间复杂度:O(nlog n) ,有一个快排
    • 空间复杂度:O(n),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间

    763.划分字母区间

    思路:

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

    可以分为如下两步:

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

    如图:

    763.划分字母区间

    代码:

    1. //手撕
    2. class Solution {
    3. private:
    4. vector<int> result;
    5. int left=0,right=0;
    6. int hash[27]={0};
    7. public:
    8. vector<int> partitionLabels(string s) {
    9. for(int i = 0; isize();i++){
    10. hash[s[i]-'a'] = i;
    11. }
    12. for(int i = 0; isize();i++){
    13. right = max(right,hash[s[i]-'a']);
    14. if(i==right){
    15. result.push_back(right-left+1);
    16. left = i+1;
    17. }
    18. }
    19. return result;
    20. }
    21. };
    22. //卡哥代码
    23. class Solution {
    24. public:
    25. vector<int> partitionLabels(string S) {
    26. int hash[27] = {0}; // i为字符,hash[i]为字符出现的最后位置
    27. for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置
    28. hash[S[i] - 'a'] = i;
    29. }
    30. vector<int> result;
    31. int left = 0;
    32. int right = 0;
    33. for (int i = 0; i < S.size(); i++) {
    34. right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界
    35. if (i == right) {
    36. result.push_back(right - left + 1);
    37. left = i + 1;
    38. }
    39. }
    40. return result;
    41. }
    42. };
    • 时间复杂度:O(n)
    • 空间复杂度:O(1),使用的hash数组是固定大小

    56. 合并区间

    思路:

    和讲过的452. 用最少数量的箭引爆气球 (opens new window)和 435. 无重叠区间 (opens new window)都是一个套路。

    这几道题都是判断区间重叠,区别就是判断区间重叠后的逻辑,本题是判断区间重贴后要进行区间合并

    所以一样的套路,先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同。

    按照左边界从小到大排序之后,如果 intervals[i][0] <= intervals[i - 1][1] 即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。(本题相邻区间也算重贴,所以是<=),本题技巧在于直接修改区间,不用删除再添加

    这么说有点抽象,看图:(注意图中区间都是按照左边界排序之后了

    56.合并区间

    代码:

    1. //手搓
    2. class Solution {
    3. private:
    4. vectorint>> result;
    5. static bool cmp(vector<int>&a,vector<int>&b){
    6. return a[0]0];
    7. }
    8. public:
    9. vectorint>> merge(vectorint>>& intervals) {
    10. sort(intervals.begin(),intervals.end(),cmp);
    11. result.push_back(intervals[0]);
    12. for(int i = 1; i < intervals.size(); i++){
    13. if(intervals[i][0]<=result.back()[1]){
    14. result.back()[1]=max(intervals[i][1],result.back()[1]);
    15. }
    16. else result.push_back(intervals[i]);
    17. }
    18. return result;
    19. }
    20. };
    21. //卡哥代码
    22. class Solution {
    23. public:
    24. vectorint>> merge(vectorint>>& intervals) {
    25. vectorint>> result;
    26. if (intervals.size() == 0) return result; // 区间集合为空直接返回
    27. // 排序的参数使用了lambda表达式
    28. sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});
    29. // 第一个区间就可以放进结果集里,后面如果重叠,在result上直接合并
    30. result.push_back(intervals[0]);
    31. for (int i = 1; i < intervals.size(); i++) {
    32. if (result.back()[1] >= intervals[i][0]) { // 发现重叠区间
    33. // 合并区间,只更新右边界就好,因为result.back()的左边界一定是最小值,因为我们按照左边界排序的
    34. result.back()[1] = max(result.back()[1], intervals[i][1]);
    35. } else {
    36. result.push_back(intervals[i]); // 区间不重叠
    37. }
    38. }
    39. return result;
    40. }
    41. };
    • 时间复杂度: O(nlogn)
    • 空间复杂度: O(logn),排序需要的空间开销
  • 相关阅读:
    Linux -- 进程间通信之匿名管道
    C++ 之 queue、stack、dueque队列
    rv1126-rv1109-openssh
    建模规范:环境设置
    TSINGSEE青犀智能分析网关如何助力别墅区域监控智能化信息化发展?
    Uni-App常用事件
    Linux内核开发——内核镜像文件及启动过程
    基于大数据的农产品价格信息监测分析系统
    微服务开发与实战Day11 - 微服务面试篇
    【算法】滑动窗口题单——2.不定长滑动窗口(求最长/最大)
  • 原文地址:https://blog.csdn.net/weixin_43793717/article/details/134513452