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 热题的解法,涵盖链表、树、动态规划等主题,欢迎持续关注!

相关推荐
叶小鸡38 分钟前
小鸡玩算法-力扣HOT100-堆
数据结构·算法·leetcode
小雅痞39 分钟前
[Java][Leetcode simple] 28. 找出字符串中第一个匹配项的下标
java·开发语言·leetcode
何陋轩1 小时前
【重磅】悟空来了:国产AI编程助手深度测评,能否吊打Copilot?
人工智能·算法·面试
逸风尊者2 小时前
XGBoost模型工程使用
java·后端·算法
LUVK_2 小时前
第七章查找
数据结构·c++·考研·算法·408
khalil10202 小时前
代码随想录算法训练营Day-31贪心算法 | 56. 合并区间、738. 单调递增的数字、968. 监控二叉树
数据结构·c++·算法·leetcode·贪心算法·二叉树·递归
lihihi3 小时前
P9936 [NFLSPC #6] 等差数列
算法
啊我不会诶3 小时前
2024ICPC西安邀请赛补题
c++·算法
谭欣辰3 小时前
C++ 版Dijkstra 算法详解
c++·算法·图论
yuan199973 小时前
C&CG(列与约束生成)算法,来解决“风光随机性”下的微网鲁棒配置问题
c语言·开发语言·算法