首页 > 编程语言 >代码随想录算法训练营第三十六天| ● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

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

时间:2024-03-04 21:00:50浏览次数:40  
标签:vector int 随想录 intervals right result 区间 第三十六

无重叠区间 

题目链接:435. 无重叠区间 - 力扣(LeetCode)

思路:我的思路是先将所有区间按左端点从小到大排序,左端点相同时右端点从小到大排序。接下来遍历数组,如果下一个区间与该区间有重叠部分,count加1,同时遍历下下一个区间(下一个区间被视为删除),同时如果下一个区间被包含在该区间中,则将当前遍历区间更改为下一个区间(该区间视为被删除)。

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end(),[](const vector< int>& u,const vector<int>& v){
            return u[0]<v[0]||(u[0]==v[0]&&u[1]<v[1]);
        });
        int count=0;
        if(intervals.size()==1)return 0;
        int start=intervals[0][0];
        int end=intervals[0][1];
        for(int i=1;i<intervals.size();i++){
            if(intervals[i][0]<end){
                if(intervals[i][1]<=end){
                    start=intervals[i][0];
                    end=intervals[i][1];
                }
                count++;
                continue;
            }
            start=intervals[i][0];
            end=intervals[i][1];
        }
        return count;

    }
};

显然我的方法有更优化的写法,按照右端点从小到大排序,在排序之后只用更新最小的右端点即可。

 int n = intervals.size();
        int right = intervals[0][1];
        int ans = 1;
        for (int i = 1; i < n; ++i) {
            if (intervals[i][0] >= right) {
                ++ans;
                right = intervals[i][1];
            }
        }
        return n - ans;

划分字母区间 

题目链接:763. 划分字母区间 - 力扣(LeetCode)

思路:有点烧脑的。我的核心思路是一个字母一个字母来,确定每一个字母出现的区间,然后再遍历字符串,不断更新当前子字符串的长度,直到遍历到子字符串的终点,将子字符串的长度存入result,然后继续遍历。

class Solution {
public:
    vector<int> partitionLabels(string s) {
        vector<vector<int>> v(26,vector<int>(2,-1));
        for(int i=0;i<s.size();i++){
            if(v[s[i]-97][0]==-1){
                v[s[i]-97][0]=i;
                v[s[i]-97][1]=i;        //不光要初始化起点,还有终点
            }
            else{
                v[s[i]-97][1]=i;
            }
        }
        vector<int> result;
        int start=0;
        int end=v[s[0]-97][1];
        for(int i=0;i<s.size();i++){
            if(i==end){
                result.push_back(end-start+1);
                start=end+1;
                    if(start!=s.size())
                        end=v[s[start]-97][1];

                 continue;
            }
            if(v[s[i]-97][1]>end){
                end=v[s[i]-97][1];
            }
        }
        return result;
    }
};

!!!∑(゚Д゚ノ)ノ注意!第二个for循环里根本没用到每个字符出现区间的起点,也就是说,我们根本不需要维护一个区间,只需要维护区间的终点就够了

class Solution {
public:
    vector<int> partitionLabels(string S) {
        int hash[27] = {0}; // i为字符,hash[i]为字符出现的最后位置
        for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置
            hash[S[i] - 'a'] = i;
        }
        vector<int> result;
        int left = 0;
        int right = 0;
        for (int i = 0; i < S.size(); i++) {
            right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界
            if (i == right) {
                result.push_back(right - left + 1);
                left = i + 1;
            }
        }
        return result;
    }
};

合并区间 

题目链接:56. 合并区间 - 力扣(LeetCode)

思路:按右端点从小到大排序,然后遍历,如果出现不重叠区间,存入result;否则同时检查是否需要更新left和right;

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
    sort(intervals.begin(),intervals.end(),[](const vector<int>& u,const vector<int>& v){
        return u[1]>v[1]||(u[1]==v[1]&&u[0]>v[0]);
    });
    int right=intervals[0][1];
    int left=intervals[0][0];
    vector<vector<int>> result;
     for(int i=1;i<intervals.size();i++){
        if(intervals[i][1]<left){
            result.push_back({left,right});
             right=intervals[i][1];
             left=intervals[i][0];
             continue;
        }
        if(intervals[i][0]<left)left=intervals[i][0];
        if(intervals[i][1]>right)right=intervals[i][1];
     }
    result.push_back({left,right});
    return result;
    }
};

 但是按左边界排序会更简单

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;
    }
};

 

标签:vector,int,随想录,intervals,right,result,区间,第三十六
From: https://www.cnblogs.com/Liubox/p/18052673

相关文章

  • Luogu P1220 关路灯 题解 [ 蓝 ][ 区间dp ]
    关路灯题目描述某一村庄在一条路线上安装了\(n\)盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少)。老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯。为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关......
  • day54 动态规划part11 代码随想录算法训练营 188. 买卖股票的最佳时机 IV
    题目:188.买卖股票的最佳时机IV我的感悟:我真棒!!理解难点:类比上一道题,掌握不好边界,就代入一个数值来推为什么是2K+1,因为要遍历到下标是[2K]听课笔记:我的代码:classSolution:defmaxProfit(self,k:int,prices:List[int])->int:iflen(prices)==1:......
  • 代码随想录 第13天 | ● 239. 滑动窗口最大值 ● 347.前 K 个高频元素 ● 总结
    leetcode:239.滑动窗口最大值-力扣(LeetCode)思路:看了挺长时间才反应过来与暴力算法的区别。当遇到比上一个元素大的值时,将上一个元素剔除,小于时加入队列中,每次等于窗口长度时将顶端也就是最大值存起来classSolution{publicint[]maxSlidingWindow(int[]nums,intk)......
  • day54 动态规划part11 代码随想录算法训练营 123. 买卖股票的最佳时机 III
    题目:123.买卖股票的最佳时机III我的感悟:困难像弹簧,你强他就弱,你弱它就强!理解难点:5个状态,听课笔记:我的代码:classSolution:defmaxProfit(self,prices:List[int])->int:iflen(prices)==1:return0#5种状态#dp[i......
  • 246. 区间最大公约数
    #include<cstdio>#include<cstring>#include<iostream>#include<algorithm>usingnamespacestd;typedeflonglongLL;constintN=500010;intn,m;LLw[N];structNode{intl,r;LLsum,d;}tr[N*4];LLgcd(LL......
  • 最大字段和,区间矩阵
    最大字段和原题链接:P1115最大子段和-洛谷|计算机科学教育新生态(luogu.com.cn)解析:经典动态规划:最大子数组问题-知乎(zhihu.com)我写的代码:#include<iostream>#include<algorithm>#include<cstring>usingnamespacestd;constintN=2e5+10;inta[N],dp[N]......
  • day52 动态规划part10 代码随想录算法训练营 122. 买卖股票的最佳时机 II
    题目:122.买卖股票的最佳时机II我的感悟:只要定义清楚,就可以做出来的。理解难点:先判断等于听课笔记:看了文字版本,感觉还是我的思路最牛逼!!我的代码:classSolution:defmaxProfit(self,prices:List[int])->int:#dp[i]为截止到当前能获得的最大利润......
  • day53 动态规划part10 代码随想录算法训练营 121. 买卖股票的最佳时机
    题目:121.买卖股票的最佳时机我的感悟:soeasy 打印dp确实能发现问题理解难点:注意条件,及时更新dp听课笔记:看了,老师的代码,感觉没有我的简洁,哈哈!!我的代码:classSolution:defmaxProfit(self,prices:List[int])->int:#设dp[i]为截止到当前能获得......
  • day52 动态规划part9 代码随想录算法训练营 337. 打家劫舍 III
    题目:337.打家劫舍III我的感悟:跳过,目前树的不学理解难点:树的理解,以及树的遍历听课笔记:我的代码:通过截图:老师代码:#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#......
  • day52 动态规划part9 代码随想录算法训练营 213. 打家劫舍 II
    题目:213.打家劫舍II我的感悟:看了题解不难,就是环这个思路转化很重要!理解难点:环的转化为,首,尾。代码上面可以省略长度为2的校验听课笔记:分3中情况:不考虑首尾|考虑首|考虑尾而情况2和情况3包含了情况1我的代码:classSolution:defrob(self,nums:List[i......