题目描述与示例

题目描述

给一个正整数 NUM1,计算出新正整数 NUM2NUM2NUM1 中移除 N 位数字后的结果,需要使得 NUM2 的值最小。

输入

  1. 输入的第一行为一个字符串,字符串由 0-9 字符组成,记录正整数 NUM1NUM1 长度小于 32
  2. 输入的第二行为需要移除的数字的个数,小于 NUM1 长度。

输出

输出一个数字字符串,记录最小值 NUM2

示例一

输入

2615371
4

输出

131

说明

移除 2657 这四个数字,剩下 131 按原有顺序排列组成 131 为最小值。

示例二

输入

12345
2

输出

123

示例三

输入

10345
2

输出

034

解题思路

注意,本题和LC402. 移掉K位数字完全一致。

代码

Python

# 题目:2023B-找最小数
# 分值:200
# 作者:闭着眼睛学数理化
# 算法:单调栈
# 代码看不懂的地方,请直接在群上提问


NUM1 = input()
n = int(input())
# rest_n 表示剩余的删除次数
rest_n = n

# 构建一个单调栈,
# 单调栈从栈底至栈顶单调递增
# 即大的数字放在栈顶
stack = list()

# 遍历数字字符串NUM1中的每一个字符ch
for ch in NUM1:
    # 出栈的情况:
    # 1. 栈不为空
    # 2. ch小于栈顶元素
    # 3. 剩余的删除次数大于0
    # 即可以弹出栈顶元素,这样才能使得栈顶元素尽可能小
    while len(stack) and ch < stack[-1] and rest_n > 0:
        stack.pop()
        rest_n -= 1
    # 对于每一个ch,都应该入栈
    stack.append(ch)

# 结束循环时,栈中元素不一定恰好为len(NUM1)-n
# 所以取较小的数前 len(NUM1)-n 个数组合成字符串
print("".join(stack[:len(NUM1)-n]))

Java

import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String NUM1 = scanner.nextLine();
        int n = scanner.nextInt();

        int rest_n = n;
        Stack<Character> stack = new Stack<>();

        for (char ch : NUM1.toCharArray()) {
            while (!stack.isEmpty() && ch < stack.peek() && rest_n > 0) {
                stack.pop();
                rest_n--;
            }
            stack.push(ch);
        }

        StringBuilder result = new StringBuilder();
        int len = NUM1.length() - n;
        for (int i = 0; i < len; i++) {
            result.append(stack.get(i));
        }

        System.out.println(result.toString());
    }
}

C++

“`C++
#include <iostream>
#include <stack>
#include <string>

using namespace std;

int main() {
string NUM1;
int n;
cin >> NUM1 >> n;

<pre><code>int rest_n = n;
stack<char> stack;

for (char ch : NUM1) {
while (!stack.empty() && ch < stack.top() && rest_n > 0) {
stack.pop();
rest_n–;
}
stack.push(ch);
}

string result;
int len = NUM1.size() – n;
while (!stack.empty()) {
result = stack.top() + result;
stack.pop();
}
result = result.substr(0, len);

cout << result << endl;

return 0;
</code></pre>

}

“`

时空复杂度

时间复杂度:O(M)。仅需一次遍历字符串NUM1

空间复杂度:O(M)。单调栈所占用的额外空间。

M为字符串NUM1的长度。

说明

华为OD机试有三道题⽬,第⼀道和第⼆道属于简单或中等题,分值为 100 分,第三道为中等或困难题,分值为 200分,总分为 400 分。

机试分数越⾼评级越⾼,⼯资也就越⾼。

关于华为 OD 机试更加详细的介绍可以查看这篇⽂章:华为OD机考须知

关于机考题目汇总可以看这篇文章:华为OD机试真题 2023 A+B+C+D卷 + 2024新卷(Python&Java&C++)⽬录汇总(每⽇更新)