LeetCode 刷题系列 -- 402. 移掉 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 不含任何前导零

402. 移掉 K 位数字 - 力扣(Leetcode)

思路

本题采用贪心 + 单调栈方法
「删除一个数字」的贪心策略:

给定一个长度为 n 的数字序列 [D0 D1 D2 D3 … Dn−1],从左往右找到第一个位置 i( 0<i<n)使得 Di<Di−1, 此时删除 Di-1 可以使得删除后的数字序列最小 ;如果不存在,说明整个数字序列单调不降,那么删去最后一个数字即可。

题目中要求的是删除 k 个数字,思路是这样的
1. 定义一个 nums_stack 单调栈
2. 从 数字序列的左边开始,将数字一次压入栈中,压入前,判断当期数字num[i] 是否比栈顶元素小,若是小的话,便将栈顶数字弹出,循环遍历直到栈顶元素不再大于 num[i] 为止。此时可以将当前元素压入 num_stack (考虑一下 0 的情况,若是num[i] == '0' ,则不压入栈中,避免出现 00123 的情况), 栈中每弹出一个数字视作删除了一个数字,记录下栈弹出的次数
3.  2步骤 中 若是删除的数字个数小于 k ,那么退出 2 中的循环后,继续弹出栈数字,直到满足删除的数字个数为k为止

c++

class Solution {
public:
    string removeKdigits(string num, int k) {
        if(num.empty()) {
            return num;
        }
        stack<char> nums_stack;

        int i = 0, count = 0;
        
        // 单调栈框架
        while(i < num.size()) {
            // 删除大于 num[i] 且在 num[i] 左边的数字
            while(count < k && !nums_stack.empty() && nums_stack.top() > num[i]) {
                nums_stack.pop();
                count += 1;
            }
            // 避免出现 000123 的情况, 所以最高位不能是 0 
            if(nums_stack.empty() && num[i] != '0' || !nums_stack.empty()) {
                nums_stack.push(num[i]);
            }
            i++;
        }

        // 经过前面的循环,nums_stack 中的数字变成了单调非递减,此时若是还有数字可以删除,那么久直接从最右边(即nums_stack 的栈顶)开始删除即可
        while(!nums_stack.empty() && count < k) {
            nums_stack.pop();
            count++;
        }

        string result;

        while(!nums_stack.empty()){
            result += nums_stack.top();
            nums_stack.pop();
        }

        // 翻转字符串
        int L = 0, R = result.size()-1;
        while(L < R) {
            char tmp = result[L];
            result[L] = result[R];
            result[R] = tmp;
            L++;
            R--;
        }

        // 说明删除后k个数字后,剩下的数字都是 0
        if(result.empty()) {
            return "0";
        }

        return result;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值