【C++算法打怪专栏】LeetCode 402. 移掉 K 位数字(单调栈 + 贪心)

【C++算法打怪专栏】LeetCode 402. 移掉 K 位数字(单调栈 + 贪心)

一、 问题描述

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

  • 示例 1 :
    • 输入:num = "1432219", k = 3
    • 输出:"1219"
    • 解释:移除掉 3 个数字 4, 3, 和 2 形成一个新的最小数字 1219。
  • 示例 2 :
    • 输入:num = "10200", k = 1
    • 输出:"200"
    • 解释:移掉首位的 1 剩下的数字为 "0200",转换为数字后即为 "200"。

二、 核心解题思路:贪心算法 + 单调栈

  1. 贪心策略 :
    从左到右扫描字符串,如果当前的数字比前一个数字小(即出现降序),为了让整体数值变小,应该优先删掉前面的大数字。
  2. 单调栈维护 :
    使用一个栈来维护一个单调递增的数字序列。遍历过程中:
    • 当栈不为空、栈顶元素大于当前字符、且还有删除次数(k > 0)时,弹出栈顶元素,并将 k 减 1。
    • 将当前字符压入栈中。
  3. 收尾与前导零处理 :
    • 如果遍历结束后 k 仍然大于 0(例如原字符串本身单调递增),则从栈顶继续弹出剩余的次数。
    • 将栈中收集的字符反转并拼成字符串,同时剔除多余的前导零。
    • 若最终结果为空,则返回 "0"。

三、 C++ 完整源代码

cpp 复制代码
#include <string>
#include <stack>
#include <algorithm>
using namespace std;

class Solution {
public:
    string removeKdigits(string num, int k) {
        int n = num.size();
        stack<char> st;
        
        // 1. 遍历字符串,利用单调栈维护局部最优解
        for(int j = 0; j < n; j++) {
            char digit = num[j];
            // 注意:必须先判断 !st.empty(),防止栈空时调用 st.top() 导致段错误
            while(!st.empty() && st.top() > digit && k > 0) {
                st.pop();
                k--;
            }
            st.push(digit);
        }
        
        // 2. 如果 k 还没用完,说明当前序列单调递增,从末尾继续删除
        while(k > 0 && !st.empty()) {
            st.pop();
            k--;
        }
        
        // 3. 将栈中元素导出并反转
        string res = "";
        while(!st.empty()) {
            res.push_back(st.top());
            st.pop();
        }
        reverse(res.begin(), res.end());
        
        // 4. 去除多余的前导零
        int l = 0;
        while(l < res.size() && res[l] == '0') {
            l++;
        }
        res = res.substr(l);
        
        // 5. 判空防错,若删光了则返回 "0"
        return res.empty() ? "0" : res;
    }
};

四、 复杂度分析

  • 时间复杂度 :O(N)O(N)O(N),其中 NNN 是字符串 num 的长度。每个字符最多被入栈和出栈一次。
  • 空间复杂度 :O(N)O(N)O(N),栈和结果字符串在最坏情况下需要占用线性级别的存储空间。
相关推荐
软件派5 小时前
生产动态数据智能风控:阈值判别、趋势预测、异常识别算法工程落地实战
前端·数据库·算法
悠仁さん12 小时前
【C++】AVL 树
c++
wuminyu12 小时前
JVM规范学习总结:解释器与JIT编译器如何处理JVM字节码
java·linux·c语言·jvm·c++
小徐不徐说12 小时前
序列化与反序列化:把 C++ 对象可靠地保存下来
开发语言·数据库·c++·php
ZhengEnCi12 小时前
模型训练完整流程:从数据准备到模型上线的 10 个关键步骤(全文可跑)
后端·算法
ragnwang12 小时前
Notes: Python pybind11 import C++ module
开发语言·c++·python
充值内卷14 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
吞下星星的少年·-·16 小时前
Div.3 CF 1131A题(排序,模拟)
算法·模拟·排序
圣保罗的大教堂16 小时前
leetcode 453. 最小操作次数使数组元素相等 中等
leetcode