移掉K位数字(单调栈)

题目描述

给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。

示例 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 。

提示:

  • 1 <= k <= num.length <= 105
  • num 仅由若干位数字(0 - 9)组成
  • 除了 0 本身之外,num 不含任何前导零

代码实现

class Solution {
public:
    string removeKdigits(string num, int k) {
        stack<char> stk;

        // 使用栈维护一个单调递增的序列,但是移除的元素不能多于k个
        for (char digit : num) {
            while (k > 0 && !stk.empty() && stk.top() > digit) {
                stk.pop();
                --k;
            }
            stk.push(digit);
        }

        // 如果 k 仍然大于 0,从栈顶移除额外的元素
        while (k > 0 && !stk.empty()) {
            stk.pop();
            --k;
        }

        // 构建结果字符串,此时栈中的序列为从底到顶的顺序
        string result;
        while (!stk.empty()) {
            result.push_back(stk.top());
            stk.pop();
        }
        reverse(result.begin(), result.end());

        // 移除结果字符串中的前导零
        int start = 0;
        while (start < result.length() && result[start] == '0') {
            ++start;
        }
        result = result.substr(start);

        return result.empty() ? "0" : result;
    }
};

算法步骤

  1. 栈的使用: 栈用于维护一个单调递增的数字序列。我们逐个遍历字符串 num 中的每个数字,并依次处理它们。

  2. 处理当前数字

    • 对于每个数字 digit,如果当前栈顶的数字大于 digit 且还可以移除更多数字(即 k > 0),则弹出栈顶元素(这意味着移除一个较大的数字)。
    • 减少 k 的值(每弹出一个数字,k 减一)。
    • 将当前数字 digit 压入栈中。
  3. 检查是否还需要移除数字

    • 如果遍历完所有数字后,k 仍大于 0,这意味着我们还需要继续从栈中移除元素,直到 k 变为 0 或栈为空。
  4. 构建结果字符串

    • 从栈底到栈顶将数字依次取出并放入结果字符串 result 中。此时,result 中的数字顺序是从高位到低位的。
    • 因为栈是后进先出的,所以需要对 result 字符串进行反转,以得到正确的顺序。
  5. 移除前导零

    • 遍历 result 字符串,从左到右检查并跳过前导零。
    • 使用 substr 方法截取掉前导零后的字符串作为最终结果。
  6. 返回最终结果

    • 如果结果字符串为空(即所有数字都被移除了),返回 "0"
    • 否则,返回处理后的字符串。

复杂度分析

  • 时间复杂度:O(N),其中 N 是字符串 num 的长度。每个元素最多被推入和弹出栈一次。
  • 空间复杂度:O(N),在最坏的情况下(例如输入的数字单调递增),栈可能需要存储所有的数字。

这个方法利用了栈的特性来维护数字的顺序,确保在遵守移除数字的限制的同时获得最小可能的数字。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LIHAORAN99

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值