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

无重叠区间 

题目链接: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;
    }
};

 

posted @   SandaiYoung  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示