尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

单调栈的“贪心”艺术:精雕细琢,打造「最小可能」的数字 - 实践

单调栈的“贪心”艺术:精雕细琢,打造「最小可能」的数字 - 实践
📅 发布时间:2026/6/22 9:35:41

单调栈的“贪心”艺术:精雕细琢,打造「最小可能」的数字 - 实践

2025-11-29 18:36  tlnshuju  阅读(0)  评论(0)    收藏  举报

哈喽各位,我是前端小L。

我们的单调栈工具箱已经很丰富了:我们用“单调递增栈”找到了最小值边界(LC 84, 907),用“单调递减栈”找到了最大值边界(LC 503, 739)。这些都是“分析型”的应用。

今天,我们的角色从“分析师”转变为“雕刻家”。我们将得到一个数字字符串和一把“锤子”(可以移除 k 个数字),我们的目标是,精心地敲掉 k 个数字,让我们手中的“石料”(数字字符串)变成一座最“小”的雕塑(最小的可能数字)。

力扣 402. 移掉 K 位数字

https://leetcode.cn/problems/remove-k-digits/

题目分析:

  • 输入:一个非负整数 num 的字符串表示,一个要移除的数字个数 k。

  • 目标:返回移除 k 个数字后,所能得到的最小可能的新数字(以字符串形式)。

例子:num = "1432219", k = 3。

  • 移除 4, 3, 2 -> 1219

  • 移除 1, 4, 3 -> 2219

  • 移除 4, 3, 9 -> 1221 ... 显然 1219 是最小的。

核心洞察:高位的“大数”是首要敌人

如何让一个数字变得尽可能小?关键在于让它的高位(左侧)数字尽可能小。12... 永远比 21... 小。

这给了我们一个清晰的贪心策略:从左到右扫描数字。当我们遇到一个数字 current,它比它前一个数字 prev 要小时,我们就发现了一个“山峰”(prev > current)。这个 prev 是一个在高位的、相对较大的数字,它阻碍了数字变小。如果我们还有移除名额(k > 0),我们应该立即移除 prev!

例如 num = "143...", k = 1

  • 看到 1。

  • 看到 4。4 > 1,暂时安全。

  • 看到 3。3 < 4!我们发现了一个“山峰” 4。13... 显然优于 14...。我们应该立即移除 4,并消耗一个 k 名额。

“Aha!”时刻:单调栈,贪心策略的完美载体!

这个“如果 current < prev,就移除 prev”的逻辑,我们该如何高效实现呢? 这不就是单调递增栈的“翻版”吗!

大家希望构建一个“结果”栈,这个栈从底到顶是单调递增的(高位小,低位大)。 当我们遍历 num 中的每个数字 d 时:

  1. “雕刻”时刻 (贪心移除):不断查看栈顶元素 stack.top()。

    • 如果 !s.empty() && k > 0 && d < s.top():

      • 找到了!当前数字 d 比栈顶(前一个我们暂时保留的数)要小。

      • “坏”的,大家就是栈顶这个“高位大数”贪心地移除它!

      • s.pop();

      • k--;

    • 继续查看新的栈顶,重复此过程,直到栈恢复递增性(或 k=0 或栈空)。

  2. “保留”时刻 (入栈):

    • s.push(d);

    • 将当前数字 d 压入栈,作为“候选”结果的一部分,它也将接受后续数字的考验。

棘手的“后处理”:三个关键细节

用单调栈处理完一遍,还剩三个细节需要“收尾”:

  1. k 还没用完怎么办?

    • 比如 num = "12345", k = 2。栈会变成 [1, 2, 3, 4, 5],k 还是2。

    • 这说明原数组已经是从左到右递增了,是最优结构。大家被迫要移除数字时,只能从末尾(低位)移除,对结果的影响最小。

    • 操作:while (k > 0) { s.pop(); k--; }

  2. 前导零怎么办?

    • 比如 num = "10200", k = 1。

    • 栈会变成 ['0', '2', '0', '0']。(1 会被 0 弹掉)。

    • 最终结果是 "0200",但应该是 "200"。

    • 操作:在从栈构建字符串后,需要一个循环来去除前导零。

  3. 结果为空怎么办?

    • 比如 num = "10", k = 2。

    • 1 被 0 弹掉。栈剩 [0]。

    • 后处理第一步,k=1,0 被弹掉。栈空了。

    • 操作:如果最终结果字符串为空,应返回 "0"。

代码实现 (使用 string 作为栈,更易处理)

用一个 string (或 vector<char>) 来充当栈,可以更方便地处理这三个“后处理”问题。

#include 
#include 
#include  // for reverse
using namespace std;
class Solution {
public:string removeKdigits(string num, int k) {string s; // 使用 string 作为栈,它就是我们构建的结果for (char d : num) {// 贪心移除:当k>0 且 栈顶元素 > 当前元素while (!s.empty() && k > 0 && s.back() > d) {s.pop_back();k--;}s.push_back(d);}// 1. k 还没用完,从末尾移除while (k > 0 && !s.empty()) {s.pop_back();k--;}// 2. 处理前导零int i = 0;// i < s.length() - 1 是为了防止 "0" 本身被移除while (i < (int)s.length() - 1 && s[i] == '0') {i++;}string result = s.substr(i);// 3. 处理结果为空return result.empty() ? "0" : result;}
};

总结:单调栈的“构造”之力

今天,我们解锁了单调栈的第三大核心能力——贪心构造。 它让我们深刻地理解到:

单调(递增)栈,是建立“保留高位小数、移除高位大数”这一贪心策略的完美数据结构。

它通过 while (d < stack.top()) 这个简单的比较,在 O(n) 的时间内,为我们完成了所有“高位大数”的“雕刻”工作。

从“找边界”到“算贡献”,再到今天的“贪心构造”,我们的单调栈工具箱已经日益强大。下一次,它又会给我们带来什么惊喜呢?

下期见!

相关新闻

  • 2025 年桐庐县摄影培训人像摄影培训推荐榜:路人贾摄影讲堂排名第一,从 0 基础到职业摄影师的进阶之路
  • 2025 年淳安县摄影培训人像摄影培训推荐榜:路人贾摄影讲堂(淳安县分公司)技艺领跑、业界金牌导师坐镇
  • 详细介绍:定制开发开源AI智能名片S2B2C商城系统:新零售革命下云零售模式的创新实践

最新新闻

  • 嵌入式硬件定时器与电源管理框架设计:Kinetis SDK HWTIMER与Power Manager深度解析
  • 南京各区黄金回收测评,正规持证店铺整理,商圈点位完整收录 - 奢侈品回收评测
  • DVWA靶场实战:从XSS漏洞到Cookie窃取与会话劫持
  • Delta模拟器终极金手指指南:从新手到高手的完整教程
  • FrankenPHP在信创环境下的适配
  • 闲置首饰出手不愁,天津添价收黄金钻戒回收门店地址汇总 - 逸程

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号