LeetCode 热题 100 刷题笔记:数组与排列的经典解法(续)

在前面的博客中,我们探讨了只出现一次的数字多数元素下一个排列寻找重复数 的解法。今天,我们继续分享买卖股票的最佳时机跳跃游戏 II划分字母区间的详细解析,涵盖解题思路、算法特性及代码实现。


六、121. 买卖股票的最佳时机

题目大意 :给定数组 prices,其中 prices[i]是第 i天的股票价格。只能选择某一天买入 ,并在未来某一天卖出 (卖出日 > 买入日),求最大利润。若无法获利,返回 0

解题思路:一次遍历找最小买入价

核心思想是动态记录"历史最低买入价",并计算当前价格与最低买入价的利润,更新最大利润:

  1. 初始化 min_price为无穷大(表示初始时没有买入价),max_profit0(初始利润为0)。

  2. 遍历每一天的价格:

    • 若当前价格 < min_price,更新 min_price为当前价格(找到更优的买入点)。

    • 否则,计算当前价格与 min_price的差值(利润),若大于 max_profit,则更新 max_profit

代码实现(C++)

复制代码
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int min_price = INT_MAX;  // 初始最小价格为无穷大
        int max_profit = 0;       // 初始最大利润为0
        for (int price : prices) {
            if (price < min_price) {
                min_price = price;  // 更新最小买入价
            } else {
                // 计算当前利润,更新最大利润
                max_profit = max(max_profit, price - min_price);
            }
        }
        return max_profit;
    }
};

算法特性

  • 时间复杂度:O(n),仅需遍历数组一次。

  • 空间复杂度:O(1),仅用两个变量记录状态。


七、45. 跳跃游戏 II

题目大意 :给定长度为 n的数组 numsnums[i]表示从索引 i向后跳的最大长度。初始在索引 0,求到达索引 n-1的最小跳跃次数。保证可以到达终点。

解题思路:贪心算法(分层跳跃)

核心思想是每次跳跃都尽可能扩展"当前能到达的最远边界",直到覆盖终点:

  1. 初始化 jumps(跳跃次数)为 0current_end(当前跳跃的边界)为 0farthest(当前能到达的最远位置)为 0

  2. 遍历数组(注意:不需要遍历最后一个元素,因为到达终点后停止):

    • 更新 farthestmax(farthest, i + nums[i])(从当前位置 i能跳到的最远位置)。

    • 若遍历到 current_end(当前跳跃的边界),说明需要再跳一次,更新 current_endfarthest,并增加 jumps

    • current_end已覆盖终点(current_end >= n-1),提前终止循环。

代码实现(C++)

复制代码
class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        int jumps = 0;       // 跳跃次数
        int current_end = 0; // 当前跳跃的边界
        int farthest = 0;    // 当前能到达的最远位置
        for (int i = 0; i < n - 1; ++i) { // 不需要遍历最后一个元素
            farthest = max(farthest, i + nums[i]); // 更新最远位置
            if (i == current_end) { // 到达当前跳跃的边界,需要再跳一次
                jumps++;
                current_end = farthest; // 更新当前跳跃的边界
                if (current_end >= n - 1) { // 已能到达终点,提前终止
                    break;
                }
            }
        }
        return jumps;
    }
};

算法特性

  • 时间复杂度:O(n),仅需遍历数组一次。

  • 空间复杂度:O(1),仅用三个变量记录状态。


八、763. 划分字母区间

题目大意 :给定字符串 s,将其划分为尽可能多的片段,使得同一字母最多出现在一个片段中。返回各片段的长度列表。

解题思路:贪心 + 哈希表记录最后位置

核心思想是先记录每个字符的最后出现位置,再遍历字符串,动态扩展当前片段的右边界,直到覆盖所有字符的最后位置

  1. 用哈希表 lastPos记录每个字符最后出现的索引。

  2. 遍历字符串,维护 start(当前片段的起始位置)和 end(当前片段的动态右边界,初始为 0):

    • 对于每个字符 s[i],更新 endmax(end, lastPos[s[i]])(确保当前片段包含该字符的最后出现位置)。

    • i == end时,说明当前片段已包含所有字符的最后出现位置,记录片段长度(end - start + 1),并更新 startend + 1

代码实现(C++)

复制代码
class Solution {
public:
    vector<int> partitionLabels(string s) {
        unordered_map<char, int> lastPos;
        // 步骤1:记录每个字符最后出现的位置
        for (int i = 0; i < s.size(); ++i) {
            lastPos[s[i]] = i;
        }
        
        vector<int> result;
        int start = 0; // 当前片段的起始位置
        int end = 0;   // 当前片段的动态右边界
        for (int i = 0; i < s.size(); ++i) {
            // 扩展当前片段的右边界,确保包含所有字符的最后出现位置
            end = max(end, lastPos[s[i]]);
            // 当前位置是片段的终点,记录长度并更新起始位置
            if (i == end) {
                result.push_back(end - start + 1);
                start = end + 1; // 下一个片段的起始位置
            }
        }
        return result;
    }
};

算法特性

  • 时间复杂度:O(n),遍历字符串两次(一次记录最后位置,一次划分片段)。

  • 空间复杂度:O(1)(或 O(26),因为字符是小写字母,哈希表最多存26个键值对)。


总结

这三类题目(股票买卖、跳跃游戏、字母划分)都属于贪心算法 的典型应用,核心思想是在每一步选择局部最优,最终得到全局最优。通过动态记录状态(如最小价格、最远跳跃位置、字符最后位置),可以在线性时间内解决问题,空间复杂度也保持在常量级。

后续我们将继续分享更多 LeetCode 热题的解法,涵盖链表、树、动态规划等主题,欢迎持续关注!

相关推荐
炽烈小老头2 小时前
【每天学习一点算法 2026/03/29】搜索二维矩阵 II
学习·算法·矩阵
靴子学长2 小时前
Qwen3.5 架构手撕源码
算法·架构·大模型
寒月小酒3 小时前
3.28 OJ
算法
打瞌睡的朱尤3 小时前
3.25蓝桥杯训练
职场和发展·蓝桥杯
AI成长日志3 小时前
【笔面试算法学习专栏】堆与优先队列专题:数组中的第K个最大元素与前K个高频元素
学习·算法·面试
雅俗共赏1003 小时前
医学图像重建中常用的正则化分类
算法
IronMurphy3 小时前
【算法三十二】
算法
Mr_Xuhhh3 小时前
LeetCode 热题 100 刷题笔记:高频面试题详解(215 & 347)
算法·leetcode·排序算法
mmz12073 小时前
贪心算法3(c++)
c++·算法·贪心算法