Day36.无重叠区间、划分字母区间、合并区间

Day36.无重叠区间、划分字母区间、合并区间

0435.无重叠区间

链接:0435.无重叠区间

在剩余区间无重叠的情况下,计算需要移除的最少区间,等价于计算可以保留的最多区间。

为了将保留的区间数量最大化,应保留结束位置最小的区间。

假设保留的区间中,结束位置最小的区间是[start1,end1],其余保留的区间的结束位置都大于等于end1
考虑区间[start2,end2],其中end2<end1,则将区间[start1,end1]替换成[start2,end2]之后,
保留的区间仍然是无重叠的,且可以保留的区间一定不会更少。

根据上述分析,可以得到贪心策略:首先将区间按结束位置升序排序,
然后每次在剩余区间中选择结束位置最小的区间保留。
该贪心策略可以将保留的区间数量最大化,将移除的区间数量最小化。

具体做法是,将区间数组intervals按结束位置升序排序。

end表示上一个保留区间的结束位置,初始时end = intervals[0]。从intervals[1]开始遍历。

对于区间intervals[i]

  • 如果intervals[i][0]>=end,说明不重叠,可以保留区间intervals[i]end更新为intervals[i][1]
  • 如果intervals[i][0]<end,说明重叠,不能保留区间intervals[i]end不变,移除区间数量+1。
class Solution {
private:
    static bool cmp(const vector<int>& a, const vector<int>& b)
    {
        return a[1] < b[1];
    }

public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals)
    {
        if (intervals.empty()) {
            return 0;
        }
        // 按照结束位置排序
        sort(intervals.begin(), intervals.end(), cmp);
        // 记录移除区间个数
        int cnt = 0;
        // 记录上一个保留区间的结束位置
        int end = intervals[0][1];
        // 从左向右遍历
        for (int i = 1; i < intervals.size(); ++i) {
            if (end <= intervals[i][0]) {
                // 区间不重叠
                end = intervals[i][1];
            } else {
                // 区间重叠
                ++cnt;
            }
        }
        return cnt;
    }
};

0763.划分字母区间

链接:0763.划分字母区间

统计每一个字符最后出现的位置

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

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

0056.合并区间

链接:0056.合并区间

直接按照左边界排序,从第二个元素开始遍历,判断有无重叠。

如果重叠,扩大有边界,然后看下一个区间,直到没有重叠为止

class Solution {
private:
    static bool cmp(const vector<int>& a, const vector<int>& b)
    {
        return a[0] < b[0];
    }

public:
    vector<vector<int>> merge(vector<vector<int>>& intervals)
    {
        vector<vector<int>> result;
        if (intervals.size() == 0) {
            return result;
        }
        sort(intervals.begin(), intervals.end(), cmp);
        bool flag = false; // 标记最后一个区间有没有合并
        int length = intervals.size();

        for (int i = 1; i < length; i++) {
            int start = intervals[i - 1][0]; // 初始为i-1区间的左边界
            int end = intervals[i - 1][1]; // 初始i-1区间的右边界
            while (i < length && intervals[i][0] <= end) { // 合并区间
                end = max(end, intervals[i][1]); // 不断更新右区间
                if (i == length - 1) {
                    flag = true; // 最后一个区间也合并了
                }
                i++; // 继续合并下一个区间
            }
            // start和end是表示intervals[i - 1]的左边界右边界,所以最优intervals[i]区间是否合并了要标记一下
            result.push_back({ start, end });
        }
        // 如果最后一个区间没有合并,将其加入result
        if (flag == false) {
            result.push_back({ intervals[length - 1][0], intervals[length - 1][1] });
        }
        return result;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值