news 2026/7/27 17:15:18

从零开始写算法——贪心篇2:买卖股票的最佳时间 + 划分字母区间

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零开始写算法——贪心篇2:买卖股票的最佳时间 + 划分字母区间

在算法中,贪心算法 (Greedy Algorithm)往往是一个让人又爱又恨的话题。爱它是因为代码通常很短,恨它是因为“当前最优选择会导致全局最优”这个逻辑有时候很难一眼看穿。

今天我们通过两道经典的 LeetCode 题目——121. 买卖股票的最佳时机763. 划分字母区间,来感受一下贪心算法如何在“一次遍历”中解决问题。

这两个题目虽然场景完全不同,但核心思想是通用的:维护一个关键的状态变量(最小值或最远边界),在遍历过程中不断更新这个状态,从而得到最终答案。


Part 1:买卖股票的最佳时机 —— 维护“历史最低点”

1. 题目核心

给定一个数组prices,它的第i个元素是一支给定股票第i天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

2. 贪心策略

我们要赚钱,核心逻辑非常简单:“低买高卖”。 但是我们不能穿越时空,我们只能在当前这一天决定:

  1. 如果在今天卖出,我能赚多少?(取决于之前的最低价是多少)。

  2. 今天是不是一个新的“历史最低点”?如果是,那以后如果想买,肯定按今天的价格买更划算。

所以,我们需要维护一个变量min_price,代表过去几天(包括今天)出现的最低股价

3. 代码实现 (C++)

你的代码中有一个非常有意思的注释,关于“先算利润还是先更新最小值”的讨论,这体现了很好的思考深度。

C++代码实现:

class Solution { public: int maxProfit(vector<int>& prices) { // 思路就是我们通过一次遍历,但是这个遍历中我们去维护最小值,以及更新答案 // min_price 初始化为第一天的价格 int ans = 0, min_price = prices[0]; for (int x : prices) { /* 这里有一个细节逻辑: 我们是先计算 ans = max(ans, x - min_price),再更新 min_price。 这意味着我们计算的是:【今天的价格 - 之前几天的最低价】。 如果你反过来,先更新 min_price,再算 ans, 那么计算的就是:【今天的价格 - 包括今天在内的历史最低价】。 如果今天就是最低价,利润算出来是 0,反正 ans 初始化也是 0, 所以这两种写法对最终结果 ans 没有影响。 */ ans = max(ans, x - min_price); min_price = min(min_price, x); } return ans; } };

4. 复杂度分析

  • 时间复杂度:O(N)

    • 我们只用了一个for循环遍历数组prices,每个元素只访问了一次。

  • 空间复杂度:O(1)

    • 我们只使用了ansmin_price两个整数变量,不需要额外的数组空间。


Part 2:划分字母区间 —— 维护“最远边界”

1. 题目核心

给你一个字符串s。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 例如:ababcbacadefegdehijhklija出现在最前面,也出现在下标 8 的位置。那么第一个片段至少要切在下标 8 之后,否则a就跨越两个片段了。

2. 贪心策略

这道题的贪心逻辑在于:一旦由于某个字母(比如 'a')被迫扩大了区间,这个区间内的所有其他字母(比如 'b', 'c')也得被包进来。

我们可以把这个问题分解为两个步骤:

  1. 预处理:每个人都想知道自己“最后出现的位置”在哪里。我们可以先遍历一遍,记下每个字母最后一次出现的下标。

  2. 合并区间

    • 我们维护一个end指针,表示当前片段至少要延伸到的位置

    • 当我们遍历到一个字符c时,看看它的最后出现位置是不是比当前的end还远?如果是,为了包住这个c,我们的片段必须延长(end变大)。

    • 何时收网?当遍历下标i追上了end时,说明这一段里所有出现过的字母,它们的最后一次出现位置都在i之前(或就是i)。此刻我们可以安全地切一刀!

3. 代码实现 (C++)

这一段代码完美诠释了“二次遍历”的思想。

C++代码实现:

class Solution { // 思路: 同一个字母最多出现在一个片段中,意味这个区间要包含所有这个字母,所以需要对区间进行划分 // 先计算每个字母对应下标,然后划分出区间,然而区间内的其他字母也会有自己对应的区间,此时应该进行合并区间 // 也就是我们目标两次遍历,第一次预处理,第二次进行划分。 public: vector<int> partitionLabels(string s) { int n = s.size(); // last 数组用来充当哈希表,记录每个字符最后出现的下标 // 大小为 26,对应 'a'-'z' int last[26]; for (int i = 0; i < n; ++i) { last[s[i] - 'a'] = i; // 不断更新,最后留下的就是最后一次出现的下标 } vector<int> ans; int start = 0, end = 0; // 第二次遍历:根据最远边界进行切割 for (int i = 0; i < n; ++i) { // 贪心核心:end 必须能包住当前字符 s[i] 的最后出现位置 end = max(end, last[s[i] - 'a']); // 如果当前的遍历下标 i 追上了 end,说明当前片段可以结束了 if(end == i) { ans.push_back(end - start + 1); // 计算当前片段长度 start = i + 1; // 更新下一个片段的起点 } } return ans; } };

4. 复杂度分析

  • 时间复杂度:O(N)

    • 虽然有两个for循环,但它们是并列的,不是嵌套的。

    • 第一个循环遍历N次构建last数组。

    • 第二个循环遍历N次进行切割。

    • 总操作次数是2N,在渐进复杂度中依然是 O(N)。

  • 空间复杂度:O(1)

    • 虽然我们开辟了一个last数组,但它的大小固定为 26(字符集大小),不随字符串长度N变化。在算法分析中,常数大小的空间视为 O(1)。

    • (注:返回值的ans数组通常不计入算法的空间复杂度,因为它用于存储结果)。


总结

这两道题虽然外表不同,但本质上都是线性扫描 + 状态更新

  1. 买卖股票:我们在扫描中更新最小值 (min),一旦遇到高价就计算利润。

  2. 划分字母:我们在扫描中更新最远边界 (end),一旦到达边界就进行切割。

这种“走一步看一步”且只需一次(或两次)遍历的方法,正是贪心算法在处理线性数据结构时的强大之处。掌握这种思维,能让你在面试中快速写出 O(N) 的高效代码。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/24 7:53:00

PPML 估计 + 一般均衡求解?ge_gravity2 一套 Stata 命令全搞定

温馨提示&#xff1a;若页面不能正常显示数学公式和代码&#xff0c;请阅读原文获得更好的阅读体验。 丁闪闪 (lianxhcn163.com) 曾咏新 厦门大学 (zengyongxinhpe163.com) 提要&#xff1a;本文系统整理了金融大语言模型 (LLM) 研究的核心资源&#xff0c;包括 12 个主流金融数…

作者头像 李华
网站建设 2026/7/24 17:13:22

leetcode 930. Binary Subarrays With Sum 和相同的二元子数组

Problem: 930. Binary Subarrays With Sum 和相同的二元子数组 前缀和&#xff0c;哈希表记录每个和所在的索引i&#xff0c;对goal0分开讨论的&#xff0c;使用前缀和- goal&#xff0c;拿到s prefixSum[i1] - goal;&#xff0c;数可能的子数组个数&#xff0c;并累加 Code …

作者头像 李华
网站建设 2026/7/27 2:20:28

探秘AI教材写作!这些工具能让你的教材生成过程低查重率

在编写教材的过程中&#xff0c;总是能精准触及“慢节奏”带来的种种问题。尽管已经准备好了框架和资料&#xff0c;却总是在内容写作上卡住——一段话反复推敲半个小时&#xff0c;还是觉得表达不够准确&#xff1b;章节间的过渡连接&#xff0c;更是绞尽脑汁也想不出合适的词…

作者头像 李华
网站建设 2026/7/22 15:51:20

四光吊舱多光谱融合技术解析

四光吊舱的多光谱融合&#xff0c;核心在于将可见光、热成像等不同波段的传感器数据进行协同处理和智能分析。这不仅能让你“看见”&#xff0c;更能让你“看透”复杂场景。多光谱融合模块的技术要点这项技术主要围绕硬件集成、算法处理和环境适应三个层面展开&#xff0c;下表…

作者头像 李华
网站建设 2026/7/27 9:36:30

AI写教材就选它!专业工具打造低查重优质教材,提升效率!

许多教材编写者常常感到遗憾&#xff1a;尽管他们精心撰写了教材的正文&#xff0c;但却因为缺少配套资源&#xff0c;导致整体的教学效果大打折扣。课后练习的题型设计需要有层次感&#xff0c;然而常常缺乏新颖的创意&#xff1b;想要制作直观的教学课件&#xff0c;却又没有…

作者头像 李华
网站建设 2026/7/22 13:58:37

为什么都说Java面试现在背八股文没用了?

很多人都说八股文没用&#xff0c;这里聊一下我对八股文的一些看法吧&#xff1a;一个知识点&#xff0c;你能把使用以及原理说出来&#xff0c;我称之为八股&#xff0c;但是你能把底层关联以及业务使用&#xff0c;优化历程也能搞清楚&#xff0c;我称之为能力&#xff1b;这…

作者头像 李华