当前位置: 首页 > news >正文

从零开始写算法——贪心篇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) 的高效代码。

http://www.jsqmd.com/news/358507/

相关文章:

  • 2026年倍克朗性价比排名,可靠的泳池漆厂家哪家好 - 工业推荐榜
  • 搞自动化的人应该都玩过电梯模型吧?今天咱们来唠唠用西门子S7-200 PLC和组态王搞五层电梯控制那点事儿。这玩意儿说难不难,但要让电梯跑得顺溜还得费点心思
  • 倍克朗专业不专业 泳池漆排名 价格合理的推荐 - myqiye
  • 屠榜级身材引爆大银幕!阿如那新戏拳击造型惊呆网友:反正很曼妙
  • HTTP 401 - {“code“:“InvalidApiKey“,“message“:“Invalid API-key provided.“,“request_id“:“d2725b0b-cb8
  • FileReader 四种主要读取方法对比
  • 江西医养结合养老院怎么选,有这些联系电话不怕找不到合适的 - mypinpai
  • 2026年精密轧机推荐厂商排行榜,实力大揭秘 - 工业品牌热点
  • 探讨深圳高新邦科技有限公司,为你揭秘其服务特色及价格 - 工业品牌热点
  • 拯救油塌发根!2026年值得入手的6款高泡控油洗发水,洗完蓬松感十足 - 华Sir1
  • 完整教程:双引擎时代:GEO与SEO如何协同重塑品牌增长路径
  • 2026年广州可靠的CE认证机构排名,高性价比CE认证授权机构分享 - 工业品网
  • 2026年南昌热门的豆包推广公司推荐,哪家口碑好且费用合理? - myqiye
  • 算法练习刷题题单 | 数学(163题)
  • 工厂设备图片素材推荐:捕捉科技感与细节瞬间 - 详解
  • 梳理值得选的滚珠丝杠生产厂,山东品牌性价比排行 - 工业设备
  • PPML 估计 + 一般均衡求解?ge_gravity2 一套 Stata 命令全搞定
  • 2026GEO行业权威推荐:圆周率——技术自研驱动的行业领航者 - 提酒换清欢
  • 2026年靠谱的导轨油服务品牌推荐,鑫瑞泽润滑油信誉有保障 - 工业品网
  • 2026年广州在职考研机构推荐,聊聊在职考研有名学校与规划 - 工业推荐榜
  • redis、mongodb、memcached 三个缓存数据库异同比较表
  • 面试高频问题-空间换时间与时间换空间
  • 算法练习刷题题单 | 动态规划(220题)
  • 设计模式的前言——Solid设计原则
  • 探讨2026年口碑不错的院史馆建设,北京三月雨集团有何独特之处 - mypinpai
  • 【小程序毕设全套源码+文档】基于Android studio的零食商城app的设计与实现(丰富项目+远程调试+讲解+定制)
  • 2026年深圳性价比高的白切鸡餐厅排名,说说白切鸡的肉质特点 - 工业品牌热点
  • 电影票房数据可视化分析系统 | Flask框架 requests Echarts 大数据 人工智能 毕业设计源码(建议收藏)✅
  • 压缩、编码、哈希与内存流
  • 【小程序毕设全套源码+文档】基于微信小程序的校园电动车租赁系统移动应用程序的设计与实现(丰富项目+远程调试+讲解+定制)