数据结构与算法学习(二)

文章目录

  • [1 贪心算法 (Greedy Algorithm)](#1 贪心算法 (Greedy Algorithm))
    • [1.1 核心思想与特点](#1.1 核心思想与特点)
    • [1.2 经典贪心类问题](#1.2 经典贪心类问题)
    • [1.3 经典问题详解与代码实现](#1.3 经典问题详解与代码实现)

1 贪心算法 (Greedy Algorithm)

  • 贪心算法是一种在每一步选择中都采取当前状态下最优(最有利)的选择,从而希望导致结果是全局最优的算法策略。

1.1 核心思想与特点

  • 核心特征:
    1. 局部最优选择: 每一步都做出当前看来最好的选择
    2. 不可回溯: 一旦做出选择,就不再回退
    3. 无后效性: 当前的选择不会影响后续子问题的结构
  • 贪心算法的适用条件:
    • 贪心性质选择: 局部最优能导致全局最优
    • 最优子结构: 问题的最优解包含子问题的最优解

1.2 经典贪心类问题

  1. 区间调度类问题
  2. 分配类问题
  3. 背包类问题
  4. 路径/图论问题
  5. 构造类问题

1.3 经典问题详解与代码实现

  • 类别一:区间调度问题
  1. 无重叠区间
cpp 复制代码
// LeetCode 435: 无重叠区间
// 问题:移除最少数量的区间,使剩余区间互不重叠
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
    if (intervals.empty()) return 0;
    
    // 按结束时间排序(贪心关键:早结束的给后面留更多空间)
    sort(intervals.begin(), intervals.end(), 
         [](const vector<int>& a, const vector<int>& b) {
             return a[1] < b[1];
         });
    
    int count = 0;  // 需要移除的区间数
    int end = intervals[0][1];
    
    for (int i = 1; i < intervals.size(); i++) {
        // 如果当前区间开始时间 < 上一个区间的结束时间,说明重叠
        if (intervals[i][0] < end) {
            count++;  // 需要移除当前区间
        } else {
            end = intervals[i][1];  // 不重叠,更新结束时间
        }
    }
    
    return count;
}

/*
示例:
输入: [[1,2],[2,3],[3,4],[1,3]]
排序后: [[1,2],[2,3],[1,3],[3,4]]
贪心选择:[1,2], [2,3], [3,4]
移除:[1,3]
输出: 1
*/
  1. 用最少数量的箭引爆气球
cpp 复制代码
// LeetCode 452: 用最少数量的箭引爆气球
int findMinArrowShots(vector<vector<int>>& points) {
    if (points.empty()) return 0;
    
    // 按结束坐标排序
    sort(points.begin(), points.end(), 
         [](const vector<int>& a, const vector<int>& b) {
             return a[1] < b[1];
         });
    
    int arrows = 1;
    int end = points[0][1];
    
    for (int i = 1; i < points.size(); i++) {
        // 如果当前气球开始位置 > 上一箭的射击位置
        if (points[i][0] > end) {
            arrows++;        // 需要新的一箭
            end = points[i][1];  // 更新射击位置
        }
        // 否则当前箭可以射爆这个气球,继续
    }
    
    return arrows;
}
  1. 视频拼接
  • 问题的关键在于,所有小于当前右节点的所有左节点中,右节点最长的那个
cpp 复制代码
// LeetCode 1024: 视频拼接
int videoStitching(vector<vector<int>>& clips, int time) {
    // 按开始时间排序,开始时间相同的按结束时间降序
    sort(clips.begin(), clips.end(), 
         [](const vector<int>& a, const vector<int>& b) {
             if (a[0] == b[0]) return a[1] > b[1];
             return a[0] < b[0];
         });
    
    int count = 0;
    int curEnd = 0, nextEnd = 0;
    int i = 0, n = clips.size();
    
    while (i < n && clips[i][0] <= curEnd) {
        // 在当前可覆盖的区间内,找能延伸到最远的
        while (i < n && clips[i][0] <= curEnd) {
            nextEnd = max(nextEnd, clips[i][1]);
            i++;
        }
        
        count++;
        curEnd = nextEnd;
        
        if (curEnd >= time) {
            return count;
        }
    }
    
    return -1;  // 无法覆盖整个区间
}
  • 类别二:分配类问题
  1. 分发饼干
cpp 复制代码
// LeetCode 455: 分发饼干
int findContentChildren(vector<int>& g, vector<int>& s) {
    // g: 孩子的胃口值,s: 饼干的尺寸
    sort(g.begin(), g.end());
    sort(s.begin(), s.end());
    
    int child = 0, cookie = 0;
    while (child < g.size() && cookie < s.size()) {
        if (s[cookie] >= g[child]) {
            child++;  // 当前饼干能满足当前孩子
        }
        cookie++;  // 无论是否满足,饼干都要被考虑
    }
    
    return child;  // 满足的孩子数量
}
相关推荐
qq_310658512 小时前
webrtc源码走读(三)核心引擎层——音频引擎
服务器·c++·音视频·webrtc
RisunJan2 小时前
【族谱】丝连族谱-EXCEL世系图排版教程
学习
嵌入式@秋刀鱼2 小时前
ROS开发学习记录【一】
linux·c++·笔记·学习
·present·2 小时前
射频网课学习第六章(功率增益圆)
学习
·present·2 小时前
射频网课第三章学习(功率增益设计)
学习
d111111111d2 小时前
STM32 I2C通信详解:从机地址 vs 寄存器地址
笔记·stm32·单片机·嵌入式硬件·学习·模块测试
蕨蕨学AI2 小时前
【2025】个人学习与实践总结
经验分享·学习·改行学it
STLearner2 小时前
2025时空数据研究工作总结
大数据·人工智能·python·深度学习·学习·机器学习·智慧城市
wdfk_prog3 小时前
[Linux]学习笔记系列 -- [fs]namei
linux·笔记·学习