贪心算法练习题(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;
    }
};
相关推荐
源客z16 分钟前
SD + Contronet,扩散模型V1.5+约束条件后续优化:保存Canny边缘图,便于视觉理解——stable diffusion项目学习笔记
图像处理·算法·计算机视觉
freyazzr41 分钟前
Leedcode刷题 | Day30_贪心算法04
数据结构·c++·算法·leetcode·贪心算法
IT猿手1 小时前
动态多目标进化算法:基于知识转移和维护功能的动态多目标进化算法(KTM-DMOEA)求解CEC2018(DF1-DF14)
算法·动态多目标进化·动态多目标进化算法·动态多目标测试·动态多目标
AI技术控1 小时前
计算机视觉算法实现——SAM实例分割:原理、实现与应用全景
人工智能·算法·计算机视觉
安科瑞刘鸿鹏1 小时前
智能配电保护:公共建筑安全的新 “防火墙”
运维·网络·物联网·算法·安全·能源
明月看潮生2 小时前
青少年编程与数学 02-016 Python数据结构与算法 16课题、贪心算法
python·算法·青少年编程·贪心算法·编程与数学
沐墨专攻技术2 小时前
顺序表专题(C语言)
c语言·开发语言·数据结构·顺序表
AI技术控2 小时前
基于YOLOv8的火车轨道检测识别系统:技术实现与应用前景
人工智能·算法·yolo·目标检测·计算机视觉
手握风云-2 小时前
巧用递归算法:破解编程难题的“秘密武器”
算法
铃煦2 小时前
《算法笔记》3.4小节——入门模拟->日期处理
笔记·算法