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

相关推荐
xieliyu.2 小时前
Java算法精讲:双指针(三)
java·开发语言·算法
一条小锦吕*3 小时前
基于Spring Boot + 数据可视化 + 协同过滤算法的推荐系统设计与实现(源码+论文+部署全讲解)
spring boot·算法·信息可视化
如竟没有火炬4 小时前
最大矩阵——单调栈
数据结构·python·线性代数·算法·leetcode·矩阵
8Qi85 小时前
LeetCode 1143 & 718:最长公共子序列 / 最长重复子数组
算法·leetcode·职场和发展·动态规划
绿算技术5 小时前
万卡推理集群存储选型分析:从核心架构到应用视角
大数据·科技·算法·架构
想吃火锅10056 小时前
【leetcode】1.两数之和js版
javascript·算法·leetcode
net3m337 小时前
一阶软件低通滤波器算法
人工智能·算法
水木流年追梦7 小时前
大模型入门-大模型优化方法12-YaRN 长文本外推技术
人工智能·分布式·算法·正则表达式·prompt
J-Tony118 小时前
【JVM】三色标记法
java·jvm·算法