【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),栈和结果字符串在最坏情况下需要占用线性级别的存储空间。
相关推荐
(Charon)1 小时前
【C++面试】线程并发与异步:区别、实现原理及使用场景
开发语言·c++
糖果豆豆2 小时前
对象是字段,还是关系?集合论和范畴论吵了三十年,答案是两个都对
算法·架构
JMchen2 小时前
实战项目一——实现一个高性能图片滤镜App
android·c++·性能优化
第六种自由2 小时前
[路飞]_Leetcode 22. 括号生成
javascript·算法·leetcode
isyoungboy2 小时前
事件驱动状态机与循环扫描状态机:两种计算模型的比较研究
算法·状态机
行者全栈架构师2 小时前
【鸿蒙心迹】从手机到平板、折叠屏——多端适配自查清单与踩坑实录(HarmonyOS 7.x)
前端·算法·架构
码匠许师傅2 小时前
【C++三方组件】libpqxx:PostgreSQL 的 C++ 客户端
开发语言·c++·postgresql
H.莓飛2 小时前
【C++】内存管理
linux·开发语言·jvm·c++·visual studio
longlongzihan3 小时前
LeetCode 24.两两交换链表中的节点:虚拟头结点与指针
算法·leetcode·链表