算法(蓝桥杯)贪心算法5——删数问题的解题思路

问题描述

给定一个高精度的正整数 n(n≤1000 位),需要删除其中任意 s 个数字,使得剩下的数字按原左右顺序组成一个新的正整数,并且这个新的正整数最小。例如,对于数字 153748,删除 2 个数字后,最小的数是 1348。


解题思路

1. 贪心算法

要解决这个问题,我们可以使用贪心算法。贪心算法在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的。

2. 维护单调递增栈

我们可以通过维护一个单调递增的栈来实现这个目标。具体步骤如下:

2.1 初始化栈

创建一个空栈 stack,用于存储最终结果中的数字。

2.2 遍历每个数字

遍历输入的高精度正整数 n 的每一位数字 num

2.3 维护单调递增栈
  • 弹出条件 :当栈不为空(stack),且还需要删除数字(s > 0),且栈顶元素大于当前数字(stack[-1] > num)时,弹出栈顶元素,并减少 s 的值。这样做的目的是尽可能地让结果数的高位更小,从而使得整个数更小。

  • 入栈操作 :将当前数字 num 入栈。这一步是为了保留当前数字,以便后续继续判断。

2.4 处理剩余的删除操作

遍历结束后,如果 s 还大于0,说明原数是单调递增的。在这种情况下,直接去掉末尾的 s 个数字即可。因为从末尾去掉数字对结果数的影响最小。

2.5 拼接结果并处理前导0
  • 拼接结果:将栈中的数字拼接成一个字符串。

  • 处理前导0 :使用 lstrip('0') 去掉前导0。如果去掉前导0后字符串为空(即原数删除后只剩下0),则返回 '0'

3. 示例解释

n = "153748"s = 2 为例,详细说明每一步的操作:

  1. 初始化栈stack = []

  2. 遍历每一位数字

    • num = '1':栈为空,直接入栈。stack = ['1']

    • num = '5':栈顶元素 '1' 小于 '5',直接入栈。stack = ['1', '5']

    • num = '3':栈顶元素 '5' 大于 '3',弹出 '5's 减1。stack = ['1']。然后 '3' 入栈。stack = ['1', '3']

    • num = '7':栈顶元素 '3' 小于 '7',直接入栈。stack = ['1', '3', '7']

    • num = '4':栈顶元素 '7' 大于 '4',弹出 '7's 减1。stack = ['1', '3']。然后 '4' 入栈。stack = ['1', '3', '4']

    • num = '8':栈顶元素 '4' 小于 '8',直接入栈。stack = ['1', '3', '4', '8']

  3. 遍历结束后s 为0,不需要再处理。

  4. 拼接结果并处理前导0''.join(stack).lstrip('0'),结果为 '1348'

最终结果为 '1348',这是删除2个数字后得到的最小数。

4. 代码实现

python 复制代码
def min_number_after_delete(n, s):
    """
    删除s个数字后得到的最小数
    :param n: 原始高精度正整数,字符串形式
    :param s: 需要删除的数字个数
    :return: 删除s个数字后得到的最小数,字符串形式
    """
    stack = []
    # 遍历每个数字
    for num in n:
        # 当栈不为空且s大于0且栈顶元素大于当前数字时,弹出栈顶元素
        while stack and s > 0 and stack[-1] > num:
            stack.pop()
            s -= 1
        # 当前数字入栈
        stack.append(num)
    
    # 如果s还大于0,说明原数是单调递增的,直接去掉末尾的s个数字即可
    if s > 0:
        stack = stack[:-s]
    
    # 将栈中的数字拼接成字符串,并去掉前导0
    return ''.join(stack).lstrip('0') or '0'

# 示例
n = "153748"
s = 2
print(min_number_after_delete(n, s))  # 输出:1348

n = "1087"
s = 1
print(min_number_after_delete(n, s))  # 输出:87

5. 总结

通过维护一个单调递增的栈,我们可以有效地找到删除 s 个数字后得到的最小数。这种方法的时间复杂度为 O(n),其中 n 是输入数字的长度,因为每个数字最多只会被入栈和出栈一次。希望这个解释能帮助你更好地理解这个问题的解法。如果有任何疑问,欢迎继续提问。

相关推荐
团子的二进制世界11 小时前
G1垃圾收集器是如何工作的?
java·jvm·算法
简佐义的博客11 小时前
生信入门进阶指南:学习顶级实验室多组学整合方案,构建肾脏细胞空间分子图谱
人工智能·学习
白日做梦Q11 小时前
Anchor-free检测器全解析:CenterNet vs FCOS
python·深度学习·神经网络·目标检测·机器学习
吃杠碰小鸡11 小时前
高中数学-数列-导数证明
前端·数学·算法
故事不长丨11 小时前
C#线程同步:lock、Monitor、Mutex原理+用法+实战全解析
开发语言·算法·c#
long31611 小时前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
近津薪荼11 小时前
dfs专题4——二叉树的深搜(验证二叉搜索树)
c++·学习·算法·深度优先
熊文豪11 小时前
探索CANN ops-nn:高性能哈希算子技术解读
算法·哈希算法·cann
喵手11 小时前
Python爬虫实战:公共自行车站点智能采集系统 - 从零构建生产级爬虫的完整实战(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集公共自行车站点·公共自行车站点智能采集系统·采集公共自行车站点导出csv
喵手11 小时前
Python爬虫实战:地图 POI + 行政区反查实战 - 商圈热力数据准备完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·地区poi·行政区反查·商圈热力数据采集