算法(蓝桥杯)贪心算法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 是输入数字的长度,因为每个数字最多只会被入栈和出栈一次。希望这个解释能帮助你更好地理解这个问题的解法。如果有任何疑问,欢迎继续提问。

相关推荐
知识分享小能手10 分钟前
Java学习教程,从入门到精通,JDBC数据库连接语法知识点及案例代码(92)
java·大数据·开发语言·数据库·学习·java开发·java后端开发
测试秃头怪15 分钟前
银行测试:第三方支付平台业务流,功能/性能/安全测试方法
自动化测试·软件测试·python·功能测试·测试工具·测试用例·安全性测试
I_Am_Me_16 分钟前
【专题一 递归】24. 两两交换链表中的节点
算法
冰茶_22 分钟前
C# 并发和并行的区别--16
开发语言·学习·c#
清弦墨客35 分钟前
【蓝桥杯】43689.包子凑数
python·蓝桥杯·编程算法
三月七(爱看动漫的程序员)43 分钟前
LARGE LANGUAGE MODELS ARE HUMAN-LEVEL PROMPT ENGINEERS
大数据·人工智能·算法·语言模型·自然语言处理·prompt
羑悻的小杀马特43 分钟前
【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)
c++·算法·图论·floyd算法
冰茶_1 小时前
C#中常见的锁以及用法--18
开发语言·学习·c#
吕小明么1 小时前
腾讯AI Lab与上交大探索模型“过度”思考
人工智能·神经网络·算法·aigc·agi
jessie的垃圾桶1 小时前
点云目标检测训练数据预处理---平面拟合与坐标转换(python实现)
python·变换矩阵·open3d·点云平面拟合