代码随想录算法训练营第三十六天

文章讲述了在C++中解决区间相关问题的优化算法,包括区间重叠计算、字母区间划分和合并区间,重点展示了如何通过比较边界值、使用vector容器以及lambda表达式来简化代码和提高效率。
摘要由CSDN通过智能技术生成

忙碌的一天,到待产的病房啦,明天迎接儿子的诞生,尽量不耽误作业,21:11,加油!!

 435. 无重叠区间

我按思路写的东西似乎过于繁琐,不过也算是憋出来了,写下来。

class Solution {
public:
    static bool cmp(const vector<int>& a,const vector<int>& b){
        if(a[1] == b[1])return (a[0] < b[0]);
        return (a[1] < b[1]);
    }
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end(),cmp);
        int chongdie = 0;
        int feijiaocha = 1;
        for(int i = 1;i < intervals.size();i++){
            if(intervals[i-1][1] > intervals[i][0]){
                chongdie++;
                intervals[i][1] = min(intervals[i][1],intervals[i-1][1]);
            }else{
                feijiaocha++;
            }
        }
        return(intervals.size() - feijiaocha);
    }
};

随想录的写法更加精简,还是以右端为排列来做。

count就是非重叠的部分

class Solution {
public:
    // 按照区间右边界排序
    static bool cmp (const vector<int>& a, const vector<int>& b) {
        return a[1] < b[1];
    }
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if (intervals.size() == 0) return 0;
        sort(intervals.begin(), intervals.end(), cmp);
        int count = 1; // 记录非交叉区间的个数
        int end = intervals[0][1]; // 记录区间分割点
        for (int i = 1; i < intervals.size(); i++) {
            if (end <= intervals[i][0]) {
                end = intervals[i][1];
                count++;
            }
        }
        return intervals.size() - count;
    }
};

 763.划分字母区间 

我写的长这样,主要问题在于需要有max_node,因为max_node在不断地增大,除非遇到的都是重复的字母直至max_node 和 i相同,说明缘分到了。随想录的基本一致,然后就是这个+1,画一下过程就可以想到。

class Solution {
public:
    vector<int> partitionLabels(string s) {
        int hash[27] = {0};
        vector<int> result;
        result.clear();
        int last_node = 0;
        int max_node = 0;
        for(int i=0;i< s.size();i++){
            hash[s[i] - 'a'] = i;
            //实际上把s里,a~z的最后一次出现的值存储到hash里
        }
        for(int i = 0; i < s.size();i++){
            max_node = max(hash[s[i] - 'a'],max_node);
            if(max_node == i){
                result.push_back(i - last_node + 1);
                last_node = i+1;
            }
        }
        return result;
    }
};

随想录补充的思路有点难想,大概是和435无重叠区间这题有点相似,把每个字母的起始和结束,做排序,然后在做重合判断。

class Solution {
public:
    static bool cmp(vector<int> &a, vector<int> &b) {
        return a[0] < b[0];
    }
    // 记录每个字母出现的区间
    vector<vector<int>> countLabels(string s) {
        vector<vector<int>> hash(26, vector<int>(2, INT_MIN));
        vector<vector<int>> hash_filter;
        for (int i = 0; i < s.size(); ++i) {
            if (hash[s[i] - 'a'][0] == INT_MIN) {
                hash[s[i] - 'a'][0] = i;
            }
            hash[s[i] - 'a'][1] = i;
        }
        // 去除字符串中未出现的字母所占用区间
        for (int i = 0; i < hash.size(); ++i) {
            if (hash[i][0] != INT_MIN) {
                hash_filter.push_back(hash[i]);
            }
        }
        return hash_filter;
    }
    vector<int> partitionLabels(string s) {
        vector<int> res;
        // 这一步得到的 hash 即为无重叠区间题意中的输入样例格式:区间列表
        // 只不过现在我们要求的是区间分割点
        vector<vector<int>> hash = countLabels(s);
        // 按照左边界从小到大排序
        sort(hash.begin(), hash.end(), cmp);
        // 记录最大右边界
        int rightBoard = hash[0][1];
        int leftBoard = 0;
        for (int i = 1; i < hash.size(); ++i) {
            // 由于字符串一定能分割,因此,
            // 一旦下一区间左边界大于当前右边界,即可认为出现分割点
            if (hash[i][0] > rightBoard) {
                res.push_back(rightBoard - leftBoard + 1);
                leftBoard = hash[i][0];
            }
            rightBoard = max(rightBoard, hash[i][1]);
        }
        // 最右端
        res.push_back(rightBoard - leftBoard + 1);
        return res;
    }
};

 56. 合并区间 

这题思路和前面的很相似,感觉以左边界排序好想一点,然后就是取最大取最小。

自己写的就很丑,因为不知道vector容器其他的玩法,看看随想录的。

看了随想录,更改了一下玩法。

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

先放进去,然后更改右边界。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值