贪心算法专题(十五):借位与填充的智慧——「单调递增的数字」

哈喽各位,我是前端L。

欢迎来到贪心算法专题第十五篇! 这道题非常有意思,有点像小学数学里的"借位减法"。 题目要求:给定一个非负整数 N,找出小于或等于 N 的最大整数,且该整数的每一位数字必须是单调递增 的(即 1234 可以,132 不行)。

力扣 738. 单调递增的数字

https://leetcode.cn/problems/monotone-increasing-digits

题目分析:

  • 输入 :n = 332

  • 输出 :299

    • 332 不行,因为 3 > 2(最后两位破坏了递增)。

    • 比它小的最大递增数是 299。

例子 2: n = 1234

  • 输出:1234 (本身就是递增的,不用变)。

例子 3: n = 10

  • 输出:9。

核心思维:一旦违规,前位减一,后位全变九

贪心策略来源于生活中的直觉: 这就好比你要把 332 变成递增。

  1. 我们发现百位 3 和十位 3 没问题。

  2. 但是十位 3 和个位 2 出问题了:3 > 2。

  3. 为了消除这个"逆序",我们必须把十位的 3 变小一点,变成 2。

  4. 既然十位变小了(高位变小了),为了让整体数值尽可能大 (题目要求最大整数),个位(以及后面所有位)就可以放飞自我,全部变成最大的数字 9。

  5. 结果:329。

等等,还没完! 变成 329 后,我们发现百位 3 和十位 2 又构成了逆序(3 > 2)。 6. 继续借位:把百位 3 减一变成 2。 7. 后面的十位变成 9。 8. 结果:299。完美!

遍历顺序:从后往前 为什么要从后往前遍历? 因为修改高位会影响低位。正如刚才的例子,332 -> 329 -> 299。如果从前往后遍历,你处理完百位和十位,再处理十位和个位时,可能会导致前面的关系失效,需要回头重做。 从后往前遍历,可以利用前面处理好的"9"的特性,一次扫描搞定。

算法流程 (JavaScript)

  1. 类型转换 :数字不好操作每一位,先转成字符串数组 strNum。

  2. 标记位 flag :记录从哪一位开始,后面的数字都要变成 9。初始化为 strNum.length(默认不需要变)。

  3. 倒序遍历 :从 i = strNum.length - 1 遍历到 1。

    • 比较 strNum[i-1] (前一位) 和 strNum[i] (当前位)。

    • 如果 strNum[i-1] > strNum[i](出现逆序,前一位太大了):

      • 前一位减 1 :strNum[i-1]--。

      • 记录标记 :flag = i。这意味着从 i 开始往后的都要变 9。

  4. 填充 9 :从 flag 到末尾,全部赋值为 '9'。

  5. 输出 :转回数字 parseInt。

代码实现

深度模拟

n = 100

  1. 数组 [1, 0, 0],flag = 3。

  2. i = 2: 比较 0 和 0。相等,没事。

  3. i = 1: 比较 1 和 0。1 > 0,出事了!

    • strNum[0] 减 1 变成 0。数组现为 [0, 0, 0]。

    • flag 更新为 1。

  4. 循环结束。

  5. 填充 9:从 flag=1 开始。

    • strNum[1] = 9

    • strNum[2] = 9

    • 数组变 [0, 9, 9]。

  6. 返回 99。正确。

总结

这道题虽然代码简单,但包含了贪心算法中**"局部调整影响全局"**的思想。

  • 局部最优:遇到逆序就借位,保证当前位不违规。

  • 全局最优:借位后把后面全变 9,保证数值最大。


下一题预告:监控二叉树

准备好了吗?我们要迎来贪心算法的最终大 Boss ------ LC 968. 监控二叉树 (Hard)。 这是一道树形 DP 和贪心结合的题目,难度远超刚才的糖果和气球。

  • 题目:给定一棵二叉树,我们在节点上安装摄像头。每个摄像头能监控自己、父节点、子节点。

  • 目标:用最少的摄像头监控整棵树。

这道题的贪心策略非常反直觉:永远不要把摄像头放在叶子节点上! 为什么?因为叶子节点放摄像头太浪费了(它没有子节点可以监控)。

这将是我们贪心专题的毕业考试,攻克它,我们就进军单调栈! 下期见!

相关推荐
ZhengEnCi22 分钟前
Agent 架构怎么选:从单 Agent 到多 Agent 编排的选型决策指南
算法·架构
秋天的怀念_David1 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Pniubi1 小时前
力扣283移动零(双指针法)
算法·leetcode·职场和发展
hhb_6181 小时前
大模型落地三重优化实战
人工智能·算法·机器学习
云和数据.ChenGuang2 小时前
光哥说Python RAG 系统需要哪些评估指标:从检索到生成的全链路评测指南
网络·人工智能·python·算法·langchain
程序员大阳2 小时前
副队长JavaScript教程(50)-DOM:网页开发的起点
javascript·dom·es·节点·概念·document·关系
2601_970703833 小时前
工业除湿机租赁:把一份租金合同拆开看
大数据·数据结构·算法·数据库架构·推荐算法
心中有你02143 小时前
Java实现Dijkstra最短路径算法(邻接表 + 优先队列)
java·数据库·算法
ZhengEnCi4 小时前
同样的模型,为什么本地和云 API 差别那么大:量化精度、聊天模板与采样参数的三大元凶
人工智能·算法·llm
Flynn Liang5 小时前
RAG 答非所问/幻觉怎么破?Spring AI QuestionAnswerAdvisor 召回优化实战(TopK/重排/混合检索)
人工智能·算法·spring·rag·幻觉·springai