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

LeetCode 435. 无重叠区间

链接:435. 无重叠区间

思路:

这道题的思路可以说是和452. 用最少数量的箭引爆气球一模一样,都是求重复区间的数量,移除区间的最小数量就等于所有区间的数量减去不重复区间的数量,减去所有重叠区间后剩余的则都是不重叠的区间。

这里采用右区间排序的办法。在左区间排序中,我们需要不断地更新rightmost,因为每次把新区间“纳入“当前区间范围内时,都需要更新rightmost到当前范围内包含的所有区间的右区间的最小值,但是在右区间排序就不用了,因为在右区间排序下,第一个位置正好就是最小的,所以只需要考虑下一个区间不在当前范围内的情况就行了。当下一个区间不在当前范围内时,更新rightmost区间并把不重复区间数量加一即可,和左区间排序的操作是一样的。最后再把所以区间数量减去不重复区间数量就行了。

代码:

class Solution {
public:
    static bool cmp(const vector<int>& lhs, const vector<int>& rhs)
    {
        return lhs[1] < rhs[1];
    }
    int eraseOverlapIntervals(vector<vector<int>>& points) {
        sort(points.begin(), points.end(), cmp);
        int count = 1;
        // 初始箭位置
        int rightmost = points[0][1];
        for (int i = 1; i < points.size(); i++)
        {
            // 如果不在当前范围内,更新当前的范围并增加区间的数量
            if (rightmost <= points[i][0])
            {
                rightmost = points[i][1];
                count++;
            }
        }
        return points.size() - count;
    }
};

LeetCode 763.划分字母区间

链接:763.划分字母区间

思路:

又是一道区间类问题,但是不能按照之前的方法做了,因为这里要处理的并不是重叠区间。一个字母只能出现在一个区间内,也就是说只要记录下每个字母最后出现的位置,那么在此之后的位置对于该字母来说都是可分割的,换句话说,在这个位置之前是一定不能分割的。所以我们需要一个哈希表来记录26个字母出现的最后位置。可以通过遍历字符串的方法更新每个字母的最后位置。

然后再次遍历字符串,用一个变量rightmost记录下当前的分割点。判断当前是否可以分割的标准为:当所有经过的字母最后出现的位置都小于等于当前下标i,则说明所有字母最后都出现在i以内,所以用rightmost表示当前经过的字母的最远下标,每次遍历都更新rightmost,取最大值,当i等于rightmost说明走到了分割点。同时我们还需要一个变量last用于储存每个区间的头的位置,因为答案要求的是每个区间的长度,所以还需要用当前下标i+1后减去头位置才是当前区间的长度。

代码:

class Solution {
public:
    vector<int> partitionLabels(string s) {
        vector<int> hashmap(26);
        for (int i = 0; i < s.size(); i++)
            hashmap[s[i] - 'a'] = i;
        int rightmost = 0;
        int last = 0;
        vector<int> ans;
        for (int i = 0; i < s.size(); i++)
        {
            // 更新最远下标
            rightmost = max(hashmap[s[i] - 'a'], rightmost);
            // 如果当前走到了最远下标
            if (i == rightmost)
            {
                ans.push_back(i + 1 - last);
                last = i + 1;
            }
        }
        return ans;
    }
};

LeetCode 56. 合并区间

链接:56. 合并区间

思路:

又是一道重叠区间问题,按照之前重叠区间问题的做法,显然是需要排序的。同样,按照左区间排序或者右区间排序都是可行的,区别只是处理的逻辑稍微有些不一样。这里以左区间排序为例,按从小到大排列,然后用一个变量rightmost记录下当前区间的右区间的最大值,从前往后遍历寻找重复区间,区别是这里我们要使合并的区间最大,所以要取右区间最大值,而不是向之前箭射气球那道题一样取最小值。

当发现下一个区间不在当前区间范围内了,说明需要一个新的区间,更新rightmost的值为新的区间的最大右区间,同时还需要把旧的区间的最大右区间也一起更新了。我们用cur表示旧区间的下标,初始时为0,当发现有新的不重叠的区间,就更新cur为新的不重叠区间的下标。

最后再次遍历数组,因为这时候我们已经更新了最大区间,把重叠的区间全部都合并了,所以只需要把更新过的区间push进最终结果里,其他的区间直接continue就可以了。

代码:

class Solution {
public:
    static bool cmp(const vector<int>& lhs, const vector<int>& rhs)
    {
        return lhs[0] < rhs[0];
    }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(), cmp);
        int rightmost = intervals[0][1];
        int cur = 0;
        for (int i = 1; i < intervals.size(); i++)
        {
            if (rightmost >= intervals[i][0])
                // 左排序取右最大值
                rightmost =  max(rightmost,intervals[i][1]);
            else
            {
                intervals[cur][1] = rightmost;
                cur = i;
                rightmost = intervals[i][1];
            }
        }
        intervals[cur][1] = rightmost;
        vector<vector<int>> ans;
        ans.push_back(intervals[0]);
        for (int i = 1; i < intervals.size(); i++)
        {
            if (intervals[i][1] <= ans[ans.size() - 1][1])
                continue;
            ans.push_back(intervals[i]);
        }
        return ans;
    }
};

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第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、付费专栏及课程。

余额充值