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

相关推荐
未来之窗软件服务3 分钟前
计算机考试-快速排序—东方仙盟
数据结构·算法·排序算法·仙盟创梦ide·东方仙盟
小龙报16 分钟前
【优选算法】1. 水果成蓝 2.找到字符串中所有字母的异位词
java·c语言·数据结构·数据库·c++·redis·算法
txzrxz1 小时前
数论:排列数、组合数、费马小定理、逆元、同余定理
c++·算法·数论·组合数·费马小定理·逆元·排列数
xqqxqxxq1 小时前
LeetCode Hot100 双指针专项题解笔记
笔记·算法·leetcode
闪电悠米2 小时前
力扣hot100-54.螺旋矩阵-模拟边界控制详解
算法·leetcode·矩阵
变量未定义~2 小时前
虚拟节点-星石传送阵(4星)、强连通分量
数据结构·算法
IT方大同2 小时前
C语言分支与循环语句
c语言·开发语言·算法
思-无-涯2 小时前
测试面试新趋势:工程思维成关键
人工智能·功能测试·测试工具·职场和发展·可用性测试
待磨的钝刨3 小时前
深入理解主成分分析(PCA)
人工智能·线性代数·算法·机器学习
wWYy.3 小时前
算法:合并两个有序数组
数据结构·算法