LeetCode 402. 移掉K位数字 | Python

402. 移掉K位数字


题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/remove-k-digits/

题目


给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:

  • num 的长度小于 10002 且 ≥ k。
  • num 不会包含任何前导零。

示例 1 :

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。

示例 2 :

输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。

示例 3 :

输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。

解题思路


思路:单调栈

先审题,题目给定一个由字符串表示的非负整数 num,要求移除 k 位数字,使得剩下的数字最小。

其中提及需注意的点如下:

  • num 不含前导零;
  • num 的长度小于 10002 且大于等于 k

那么现在的问题就是,如何确定移除的数字,使得剩余数字最小?

先说下数字比较的问题。当比较非负整数大小时,在不含前导零的情况下,且数字位数相同时,我们需要逐位对比数字的大小,然后确定整体数字的大小。例如:

# 比较相同位数的 123 和 132
123
132

首位 1 相同,但第二位中 1323 大于 123 中的 2,所以 132 > 123

也即是说,当两个数字位数相同(两数不等)的情况下,由高位决定大小。

回到本题,现在我们要考虑移除 k 位数字,要想最终得到数字最小,那么我们应该从移除高位较大的数字,保留较小的数字。以示例 1 来进行说明:

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。

这里 k3,需要移除 3 位数字。这里说明下移除 1 位的情况(因为后续的情况思路也是相同的)。

在前面的分析中我们可知,两个数字位数相同(两数不等)的情况,高位决定大小。例子中 "1432219",我们可以移除任意一个数字,而得到的剩余数字的位数都是相同的。在这里,输出中先将 4 移除,保留剩下的数字,即是优先移除高位较大的数字。

题目中给定的数字是以字符串表示的,那么假设我们将数字用列表的形式表示,现在我们要找高位较大的数字时,做法如下:

从左到右遍历列表,当找到 i ( i > 0 ) i(i > 0) ii>0,使得 n u m [ i − 1 ] > n u m [ i ] num[i-1] > num[i] num[i1]>num[i],那么这里我们就可以确定,在这个区间中 n u m [ i − 1 ] num[i-1] num[i1] 是较大的数字,考虑将其移除。若还需继续移除数字,以同样的做法进行。

这里需要注意,若无法找到 i i i 满足上面的条件时,则表示这个序列是(不严格的)单调递增的,那么可以从序列后面开始移除。

这里不严格的单调递增,表示序列数字可能存在相等的情况。

单调栈

在这里,我们可以考虑使用单调栈的思路来实现上面的策略。

具体的思路如下:

  • 定义栈,从左往右开始遍历字符串;
  • 进行比较,如果遍历的数字小于栈顶的元素,那么进行出栈。
  • 当满足以下条件时,停止出栈:
    • 出栈元素的次数达到 k 次;
    • 栈为空;
    • 栈顶元素不再大于遍历的数字。
  • 若不满足上面的条件时,继续入栈直至遍历结束。

当遍历结束后,这里还需要注意一些问题:

  • 当出栈的数字个数小于 k 时,也即是移除的数字个数不够时,由于此时的栈是单调不减的,那么直接从尾部移除剩下的数字;
  • 如果剩余数字存在前导零的情况时,我们要将前导零删除;
  • 如果最终数字为空时,返回字符串 '0'

具体代码实现如下。

class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        # 定义栈
        stack = []

        # 开始遍历
        for digit in num:
            # 数组 num 的长度一定是大于或等于 k 的
            # 如果栈顶数字大于遍历数字时,出栈
            while k > 0 and stack and stack[-1] > digit:
                stack.pop()
                k -= 1
            
            # 否则入栈
            stack.append(digit)
        
        # 若此时栈为单调递增栈,但是还未移除完 k 位数字
        # 直接从栈顶移除数字,这里 python 直接用列表切片
        ans = stack[:-k] if k > 0 else stack

        # 注意前导 0 的情况
        return ''.join(ans).lstrip('0') or '0'

欢迎关注


公众号 【书所集录


如有错误,烦请指出,欢迎指点交流。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值