贪心算法练习题(7/2)

1无重叠区间

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠

示例 1:

复制代码
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

复制代码
输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

复制代码
输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

提示:

  • 1 <= intervals.length <= 105
  • intervals[i].length == 2
  • -5 * 104 <= starti < endi <= 5 * 104

思路:

  1. 按起始位置排序

    • 首先,根据区间的起始位置对它们进行排序。这种排序可以有效地通过确保按起始位置顺序处理区间来检查重叠。
  2. 贪心策略

    • 初始化 count 为 0,用于记录需要移除的重叠区间数量。
    • 遍历排序后的区间,从第二个区间开始。
    • 对于每个区间,检查其起始位置是否小于前一个区间的结束位置。这表示存在重叠。
    • 如果存在重叠:
      • 增加 count
      • 更新当前区间的结束位置为其当前结束位置与前一个区间结束位置的最小值。这确保当前区间调整以消除与前一个区间的重叠。
  3. 结果

    • 循环结束时,count 的值即为最大可保留的不重叠区间数量。

代码:

cpp 复制代码
class Solution {
public:
    // 自定义比较函数,按照区间起始位置从小到大排序
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        return a[0] < b[0];
    }
    // 求解无重叠区间的最大数量
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        // 若区间数量为0,返回0
        if (intervals.size() == 0) return 0;
        // 按照区间起始位置排序
        sort(intervals.begin(), intervals.end(), cmp);
        int count = 0; // 记录重叠区间数量
        // 遍历区间数组
        for (int i = 1; i < intervals.size(); i++) {
            // 若当前区间起始位置小于前一个区间的结束位置,说明存在重叠
            if (intervals[i][0] < intervals[i - 1][1]) {
                count++; // 计数加1
                // 更新当前区间的结束位置为前一个区间结束位置与当前区间结束位置的最小值
                intervals[i][1] = min(intervals[i - 1][1], intervals[i][1]);
            }
        }
        return count; // 返回重叠区间数量
    }
};

2划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s

返回一个表示每个字符串片段的长度的列表。

示例 1:

复制代码
输入:s = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。 

示例 2:

复制代码
输入:s = "eccbbbbdec"
输出:[10]

提示:

  • 1 <= s.length <= 500
  • s 仅由小写英文字母组成

思路:在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。

  1. 统计字符出现的最后位置

    • 使用一个数组 hash,其中 hash[i] 记录字符 'a' + i 最后一次出现的位置。
  2. 贪心策略

    • 使用两个指针 leftright 来表示当前区间的起始和结束位置。
    • 遍历字符串 S,对于每个字符,更新 right 为当前字符的最后出现位置。
    • 如果当前遍历的位置 i 等于 right,则表示当前区间可以划分,将当前区间的长度加入结果中,并更新 left 到下一个字符的位置。
  3. 结果

    • 遍历完成后,得到所有划分区间的长度,即为最终结果。

代码:

cpp 复制代码
class Solution {
public:
    vector<int> partitionLabels(string S) {
        int hash[26] = {0}; // 存储每个字符的最后出现位置
        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;
    }
};
相关推荐
tainshuai1 小时前
用 KNN 算法解锁分类的奥秘:从电影类型到鸢尾花开
算法·分类·数据挖掘
Coovally AI模型快速验证7 小时前
农田扫描提速37%!基于检测置信度的无人机“智能抽查”路径规划,Coovally一键加速模型落地
深度学习·算法·yolo·计算机视觉·transformer·无人机
pusue_the_sun7 小时前
数据结构:二叉树oj练习
c语言·数据结构·算法·二叉树
RaymondZhao348 小时前
【全面推导】策略梯度算法:公式、偏差方差与进化
人工智能·深度学习·算法·机器学习·chatgpt
zhangfeng11338 小时前
DBSCAN算法详解和参数优化,基于密度的空间聚类算法,特别擅长处理不规则形状的聚类和噪声数据
算法·机器学习·聚类
圣保罗的大教堂9 小时前
leetcode 2348. 全 0 子数组的数目 中等
leetcode
啊阿狸不会拉杆9 小时前
《算法导论》第 32 章 - 字符串匹配
开发语言·c++·算法
小学生的信奥之路9 小时前
洛谷P3817题解:贪心算法解决糖果分配问题
c++·算法·贪心算法
你知道网上冲浪吗10 小时前
【原创理论】Stochastic Coupled Dyadic System (SCDS):一个用于两性关系动力学建模的随机耦合系统框架
python·算法·数学建模·数值分析
地平线开发者11 小时前
征程 6 | PTQ 精度调优辅助代码,总有你用得上的
算法·自动驾驶