【2024年华为OD机试】 (B卷,100分)- 找最小数(Java & JS & Python&C/C++)

一、问题描述

题目描述

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

输入描述

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

输出描述

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

用例

用例 1

输入:

2615371
4

输出:

131

题目解析

为了得到最小的 NUM2,我们需要从 NUM1 中移除 N 位数字。移除数字的策略是:

  1. 从左到右遍历 NUM1,尽可能移除较大的数字,以使剩余的数字最小。
  2. 如果遇到相同的数字,优先移除靠后的数字,以保持剩余数字的顺序。

详细步骤

  1. 读取输入

    • 读取正整数 NUM1
    • 读取需要移除的数字个数 N
  2. 初始化栈

    • 创建一个空栈 stack,用于存储最终的 NUM2
  3. 遍历 NUM1

    • 遍历 NUM1 中的每个数字 digit
      • 如果 stack 不为空且 stack 的栈顶元素大于 digit,并且 N 大于 0:
        • 弹出 stack 的栈顶元素。
        • N 减 1。
      • digit 压入 stack
  4. 处理剩余的 N

    • 如果 N 仍然大于 0,从 stack 的末尾移除 N 个元素。
  5. 构建 NUM2

    • stack 中的元素拼接成字符串,得到 NUM2
  6. 输出结果

    • 输出 NUM2

用例解释

用例 1
  • 输入:
    • NUM1 = 2615371
    • N = 4
  • 输出:
    • 131

解释

  • 遍历 2615371
    • 2 -> 压入 stackstack = [2]
    • 6 -> 压入 stackstack = [2, 6]
    • 1 -> stack 的栈顶元素 6 大于 1,弹出 6N = 3stack = [2]
    • 5 -> 压入 stackstack = [2, 5]
    • 3 -> stack 的栈顶元素 5 大于 3,弹出 5N = 2stack = [2]
    • 7 -> 压入 stackstack = [2, 7]
    • 1 -> stack 的栈顶元素 7 大于 1,弹出 7N = 1stack = [2]
  • 处理剩余的 N
    • stack 的末尾移除 1 个元素,stack = [1]
  • 构建 NUM2
    • stack 中的元素拼接成字符串,得到 131

通过上述步骤,我们可以高效地求出最小的 NUM2。这种方法的时间复杂度为 O(n),其中 nNUM1 的长度。

二、JavaScript算法源码

以下是带有详细中文注释和讲解的 JavaScript 代码:

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

// 创建 readline 接口,用于从控制台读取输入
const rl = readline.createInterface({
  input: process.stdin,  // 输入流为标准输入
  output: process.stdout, // 输出流为标准输出
});

// 存储输入行的数组
const lines = [];

// 监听 'line' 事件,每次读取一行输入
rl.on("line", (line) => {
  // 将输入行添加到 lines 数组中
  lines.push(line);

  // 当读取到两行输入时,开始处理
  if (lines.length === 2) {
    // 将第一行输入转换为数字数组
    const arr = lines[0].split("").map((ele) => parseInt(ele));
    // 获取第二行输入,表示需要移除的字符数量
    const removeCount = lines[1];

    // 调用 getMinValue 方法并输出结果
    console.log(getMinValue(arr, removeCount));
  }
});

/**
 * 获取移除指定数量字符后的最小数字字符串
 * @param {number[]} arr 原始数字数组
 * @param {number} removeCount 需要移除的字符数量
 * @returns {string} 移除指定数量字符后的最小数字字符串
 */
function getMinValue(arr, removeCount) {
  // 如果移除的字符数量等于数组长度,直接返回 "0"
  if (arr.length === removeCount) return "0";

  // 计算需要保留的字符数量
  let remainCount = arr.length - removeCount;

  // 使用数组模拟栈结构
  let stack = [];
  for (let i = 0; i < arr.length; i++) {
    // 当栈不为空、仍有字符需要移除、且栈顶字符大于当前字符时
    while (
      stack.length > 0 &&
      removeCount > 0 &&
      stack[stack.length - 1] > arr[i]
    ) {
      // 移除栈顶字符(保证结果最小)
      stack.pop();
      // 减少需要移除的字符数量
      removeCount--;
    }
    // 将当前字符压入栈中
    stack.push(arr[i]);
  }

  // 如果栈中字符数量超过需要保留的数量,移除多余的字符
  while (stack.length > remainCount) {
    stack.pop();
  }

  // 移除前导零(如果存在且栈中字符数量大于 1)
  while (stack[0] === 0 && stack.length !== 1) {
    stack.shift();
  }

  // 将栈中的字符拼接成字符串并返回
  return stack.join("");
}

代码讲解

1. 输入处理部分
  • readline 模块
    • 使用 readline 模块从控制台读取输入。
    • 通过 rl.on('line', callback) 监听每一行的输入。
  • 输入存储
    • 将每一行输入存储在 lines 数组中。
    • 当读取到两行输入时,开始处理数据。

2. getMinValue 方法
  • 功能
    • 从原始数字数组 arr 中移除 removeCount 个字符,使得剩下的字符组成的数字最小。
  • 实现逻辑
    1. 特殊情况处理
      • 如果 removeCount 等于 arr 的长度,直接返回 "0"
    2. 计算需要保留的字符数量
      • remainCount = arr.length - removeCount
    3. 使用栈结构优化结果
      • 遍历 arr 的每个字符:
        • 如果栈不为空、仍有字符需要移除、且栈顶字符大于当前字符,则移除栈顶字符(保证结果最小)。
        • 将当前字符压入栈中。
    4. 移除多余的字符
      • 如果栈中字符数量超过 remainCount,移除多余的字符。
    5. 移除前导零
      • 如果栈顶字符是 0 且栈中字符数量大于 1,移除前导零。
    6. 拼接结果
      • 将栈中的字符拼接成字符串并返回。

3. 核心思想
  • 贪心算法
    • 通过栈结构,每次移除比当前字符大的栈顶字符,确保结果最小。
  • 栈的作用
    • 栈用于动态维护当前最小的字符序列。
  • 时间复杂度
    • 由于每个字符最多入栈和出栈一次,时间复杂度为 O(n),其中 n 是 arr 的长度。

示例

输入
1432219
3
执行过程
  1. 初始化栈为空。
  2. 遍历字符:
    • 1:压入栈,栈为 [1]
    • 4:压入栈,栈为 [1, 4]
    • 3:发现栈顶 4 大于 3,移除 4,栈为 [1, 3]
    • 2:发现栈顶 3 大于 2,移除 3,栈为 [1, 2]
    • 2:压入栈,栈为 [1, 2, 2]
    • 1:发现栈顶 2 大于 1,移除 2,栈为 [1, 2, 1]
    • 9:压入栈,栈为 [1, 2, 1, 9]
  3. 移除多余的字符(如果需要)。
  4. 移除前导零(如果需要)。
  5. 拼接结果:"1219"
输出
1219

总结

  • 该代码通过贪心算法和栈结构,高效地解决了“移除指定数量字符后得到最小数字”的问题。
  • 代码逻辑清晰,注释详细,适合学习和参考。

如果有其他问题,欢迎继续提问!

三、Java算法源码

以下是带有详细中文注释和讲解的代码:

import java.util.LinkedList;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    // 创建 Scanner 对象用于读取输入
    Scanner sc = new Scanner(System.in);

    // 读取第一行输入,表示原始数字字符串
    String num1 = sc.nextLine();
    // 读取第二行输入,表示需要移除的字符数量
    int count = Integer.parseInt(sc.nextLine());

    // 调用 getResult 方法并输出结果
    System.out.println(getResult(num1, count));
  }

  /**
   * 获取移除指定数量字符后的最小数字字符串
   * @param num1 原始数字字符串
   * @param removeCount 需要移除的字符数量
   * @return 移除指定数量字符后的最小数字字符串
   */
  private static String getResult(String num1, int removeCount) {
    // 如果移除的字符数量等于字符串长度,直接返回 "0"
    if (num1.length() == removeCount) return "0";

    // 计算需要保留的字符数量
    int remainCount = num1.length() - removeCount;

    // 使用 LinkedList 模拟栈结构
    LinkedList<Character> stack = new LinkedList<>();
    for (int i = 0; i < num1.length(); i++) {
      // 当栈不为空、仍有字符需要移除、且栈顶字符大于当前字符时
      while (stack.size() > 0 && removeCount > 0 && stack.getLast() > num1.charAt(i)) {
        // 移除栈顶字符(保证结果最小)
        stack.removeLast();
        // 减少需要移除的字符数量
        removeCount--;
      }
      // 将当前字符压入栈中
      stack.add(num1.charAt(i));
    }

    // 如果栈中字符数量超过需要保留的数量,移除多余的字符
    while (stack.size() > remainCount) {
      stack.removeLast();
    }

    // 移除前导零(如果存在且栈中字符数量大于 1)
    while (stack.getFirst() == '0' && stack.size() != 1) {
      stack.removeFirst();
    }

    // 将栈中的字符拼接成最终结果
    StringBuilder sb = new StringBuilder();
    for (Character c : stack) sb.append(c);
    return sb.toString();
  }
}

代码讲解

1. 主函数 main
  • 输入读取
    • 使用 Scanner 读取两行输入:
      • 第一行是原始数字字符串 num1
      • 第二行是需要移除的字符数量 count
  • 调用 getResult 方法
    • num1count 作为参数传递给 getResult 方法,获取结果并输出。

2. getResult 方法
  • 功能
    • 从原始数字字符串 num1 中移除 removeCount 个字符,使得剩下的字符串表示的数字最小。
  • 实现逻辑
    1. 特殊情况处理
      • 如果 removeCount 等于 num1 的长度,直接返回 "0"
    2. 计算需要保留的字符数量
      • remainCount = num1.length() - removeCount
    3. 使用栈结构优化结果
      • 遍历 num1 的每个字符:
        • 如果栈不为空、仍有字符需要移除、且栈顶字符大于当前字符,则移除栈顶字符(保证结果最小)。
        • 将当前字符压入栈中。
    4. 移除多余的字符
      • 如果栈中字符数量超过 remainCount,移除多余的字符。
    5. 移除前导零
      • 如果栈顶字符是 '0' 且栈中字符数量大于 1,移除前导零。
    6. 拼接结果
      • 将栈中的字符拼接成字符串并返回。

3. 核心思想
  • 贪心算法
    • 通过栈结构,每次移除比当前字符大的栈顶字符,确保结果最小。
  • 栈的作用
    • 栈用于动态维护当前最小的字符序列。
  • 时间复杂度
    • 由于每个字符最多入栈和出栈一次,时间复杂度为 O(n),其中 n 是 num1 的长度。

示例

输入
1432219
3
执行过程
  1. 初始化栈为空。
  2. 遍历字符:
    • '1':压入栈,栈为 ['1']
    • '4':压入栈,栈为 ['1', '4']
    • '3':发现栈顶 '4' 大于 '3',移除 '4',栈为 ['1', '3']
    • '2':发现栈顶 '3' 大于 '2',移除 '3',栈为 ['1', '2']
    • '2':压入栈,栈为 ['1', '2', '2']
    • '1':发现栈顶 '2' 大于 '1',移除 '2',栈为 ['1', '2', '1']
    • '9':压入栈,栈为 ['1', '2', '1', '9']
  3. 移除多余的字符(如果需要)。
  4. 移除前导零(如果需要)。
  5. 拼接结果:"1219"
输出
1219

总结

  • 该代码通过贪心算法和栈结构,高效地解决了“移除指定数量字符后得到最小数字”的问题。
  • 代码逻辑清晰,注释详细,适合学习和参考。

如果有其他问题,欢迎继续提问!

四、Python算法源码

以下是带有详细中文注释和讲解的 Python 代码:

# 输入获取
num1 = input()  # 读取第一行输入,表示原始数字字符串
removeCount = int(input())  # 读取第二行输入,表示需要移除的字符数量


# 算法入口
def getResult(num1, removeCount):
    # 如果移除的字符数量等于字符串长度,直接返回 "0"
    if len(num1) == removeCount:
        return "0"

    # 计算需要保留的字符数量
    remainCount = len(num1) - removeCount

    # 使用列表模拟栈结构
    stack = []
    for i in range(len(num1)):
        # 当栈不为空、仍有字符需要移除、且栈顶字符大于当前字符时
        while len(stack) > 0 and removeCount > 0 and stack[-1] > num1[i]:
            # 移除栈顶字符(保证结果最小)
            stack.pop()
            # 减少需要移除的字符数量
            removeCount -= 1
        # 将当前字符压入栈中
        stack.append(num1[i])

    # 如果栈中字符数量超过需要保留的数量,移除多余的字符
    while len(stack) > remainCount:
        stack.pop()

    # 移除前导零(如果存在且栈中字符数量大于 1)
    while stack[0] == '0' and len(stack) != 1:
        stack.pop(0)

    # 将栈中的字符拼接成字符串并返回
    return "".join(stack)


# 算法调用
print(getResult(num1, removeCount))

代码讲解

1. 输入获取部分
  • input() 函数
    • 使用 input() 函数从控制台读取输入。
    • 第一行输入是原始数字字符串 num1
    • 第二行输入是需要移除的字符数量 removeCount

2. getResult 方法
  • 功能
    • 从原始数字字符串 num1 中移除 removeCount 个字符,使得剩下的字符串表示的数字最小。
  • 实现逻辑
    1. 特殊情况处理
      • 如果 removeCount 等于 num1 的长度,直接返回 "0"
    2. 计算需要保留的字符数量
      • remainCount = len(num1) - removeCount
    3. 使用栈结构优化结果
      • 遍历 num1 的每个字符:
        • 如果栈不为空、仍有字符需要移除、且栈顶字符大于当前字符,则移除栈顶字符(保证结果最小)。
        • 将当前字符压入栈中。
    4. 移除多余的字符
      • 如果栈中字符数量超过 remainCount,移除多余的字符。
    5. 移除前导零
      • 如果栈顶字符是 '0' 且栈中字符数量大于 1,移除前导零。
    6. 拼接结果
      • 将栈中的字符拼接成字符串并返回。

3. 核心思想
  • 贪心算法
    • 通过栈结构,每次移除比当前字符大的栈顶字符,确保结果最小。
  • 栈的作用
    • 栈用于动态维护当前最小的字符序列。
  • 时间复杂度
    • 由于每个字符最多入栈和出栈一次,时间复杂度为 O(n),其中 n 是 num1 的长度。

示例

输入
1432219
3
执行过程
  1. 初始化栈为空。
  2. 遍历字符:
    • '1':压入栈,栈为 ['1']
    • '4':压入栈,栈为 ['1', '4']
    • '3':发现栈顶 '4' 大于 '3',移除 '4',栈为 ['1', '3']
    • '2':发现栈顶 '3' 大于 '2',移除 '3',栈为 ['1', '2']
    • '2':压入栈,栈为 ['1', '2', '2']
    • '1':发现栈顶 '2' 大于 '1',移除 '2',栈为 ['1', '2', '1']
    • '9':压入栈,栈为 ['1', '2', '1', '9']
  3. 移除多余的字符(如果需要)。
  4. 移除前导零(如果需要)。
  5. 拼接结果:"1219"
输出
1219

总结

  • 该代码通过贪心算法和栈结构,高效地解决了“移除指定数量字符后得到最小数字”的问题。
  • 代码逻辑清晰,注释详细,适合学习和参考。

如果有其他问题,欢迎继续提问!

五、C/C++算法源码:

以下是 C++C语言 版本的代码实现,并附带详细的中文注释和讲解。


C++ 版本

#include 
#include 
#include 
using namespace std;

// 算法入口
string getResult(string num1, int removeCount) {
    // 如果移除的字符数量等于字符串长度,直接返回 "0"
    if (num1.length() == removeCount) {
        return "0";
    }

    // 计算需要保留的字符数量
    int remainCount = num1.length() - removeCount;

    // 使用 vector 模拟栈结构
    vector<char> stack;
    for (int i = 0; i < num1.length(); i++) {
        // 当栈不为空、仍有字符需要移除、且栈顶字符大于当前字符时
        while (!stack.empty() && removeCount > 0 && stack.back() > num1[i]) {
            // 移除栈顶字符(保证结果最小)
            stack.pop_back();
            // 减少需要移除的字符数量
            removeCount--;
        }
        // 将当前字符压入栈中
        stack.push_back(num1[i]);
    }

    // 如果栈中字符数量超过需要保留的数量,移除多余的字符
    while (stack.size() > remainCount) {
        stack.pop_back();
    }

    // 移除前导零(如果存在且栈中字符数量大于 1)
    while (stack.size() > 1 && stack[0] == '0') {
        stack.erase(stack.begin());
    }

    // 将栈中的字符拼接成字符串并返回
    string result(stack.begin(), stack.end());
    return result;
}

int main() {
    // 输入获取
    string num1;
    int removeCount;
    cin >> num1 >> removeCount;

    // 算法调用
    cout << getResult(num1, removeCount) << endl;

    return 0;
}

C++ 代码讲解

  1. 输入获取

    • 使用 cin 从控制台读取输入。
    • num1 是原始数字字符串。
    • removeCount 是需要移除的字符数量。
  2. getResult 方法

    • 功能:从 num1 中移除 removeCount 个字符,使得剩下的字符串表示的数字最小。
    • 实现逻辑
      • 使用 vector 模拟栈结构。
      • 遍历 num1 的每个字符,通过贪心算法移除比当前字符大的栈顶字符。
      • 移除多余的字符和前导零。
      • 将栈中的字符拼接成字符串并返回。
  3. 核心思想

    • 贪心算法:通过栈结构动态维护最小的字符序列。
    • 时间复杂度:O(n),其中 n 是 num1 的长度。
  4. 示例

    • 输入:
      1432219
      3
      
    • 输出:
      1219
      

C 语言版本

#include 
#include 
#include 

// 算法入口
char* getResult(char* num1, int removeCount) {
    int len = strlen(num1);

    // 如果移除的字符数量等于字符串长度,直接返回 "0"
    if (len == removeCount) {
        char* result = (char*)malloc(2 * sizeof(char));
        result[0] = '0';
        result[1] = '\0';
        return result;
    }

    // 计算需要保留的字符数量
    int remainCount = len - removeCount;

    // 使用数组模拟栈结构
    char* stack = (char*)malloc((len + 1) * sizeof(char));
    int top = -1; // 栈顶指针

    for (int i = 0; i < len; i++) {
        // 当栈不为空、仍有字符需要移除、且栈顶字符大于当前字符时
        while (top >= 0 && removeCount > 0 && stack[top] > num1[i]) {
            // 移除栈顶字符(保证结果最小)
            top--;
            // 减少需要移除的字符数量
            removeCount--;
        }
        // 将当前字符压入栈中
        stack[++top] = num1[i];
    }

    // 如果栈中字符数量超过需要保留的数量,移除多余的字符
    while (top + 1 > remainCount) {
        top--;
    }

    // 移除前导零(如果存在且栈中字符数量大于 1)
    int start = 0;
    while (start <= top && stack[start] == '0') {
        start++;
    }

    // 如果所有字符都被移除,返回 "0"
    if (start > top) {
        char* result = (char*)malloc(2 * sizeof(char));
        result[0] = '0';
        result[1] = '\0';
        free(stack);
        return result;
    }

    // 将栈中的字符拼接成字符串并返回
    char* result = (char*)malloc((top - start + 2) * sizeof(char));
    int index = 0;
    for (int i = start; i <= top; i++) {
        result[index++] = stack[i];
    }
    result[index] = '\0';

    free(stack);
    return result;
}

int main() {
    // 输入获取
    char num1[1000];
    int removeCount;
    scanf("%s", num1);
    scanf("%d", &removeCount);

    // 算法调用
    char* result = getResult(num1, removeCount);
    printf("%s\n", result);

    // 释放动态分配的内存
    free(result);

    return 0;
}

C 语言代码讲解

  1. 输入获取

    • 使用 scanf 从控制台读取输入。
    • num1 是原始数字字符串。
    • removeCount 是需要移除的字符数量。
  2. getResult 方法

    • 功能:从 num1 中移除 removeCount 个字符,使得剩下的字符串表示的数字最小。
    • 实现逻辑
      • 使用数组模拟栈结构。
      • 遍历 num1 的每个字符,通过贪心算法移除比当前字符大的栈顶字符。
      • 移除多余的字符和前导零。
      • 将栈中的字符拼接成字符串并返回。
  3. 核心思想

    • 贪心算法:通过数组模拟栈结构动态维护最小的字符序列。
    • 时间复杂度:O(n),其中 n 是 num1 的长度。
  4. 示例

    • 输入:
      1432219
      3
      
    • 输出:
      1219
      
  5. 内存管理

    • 使用 malloc 动态分配内存,并在使用完毕后通过 free 释放内存。

总结

  • C++C语言 版本的代码逻辑与 Python 版本一致,均通过贪心算法和栈结构实现。
  • C++ 使用了 vector 模拟栈,代码更简洁。
  • C语言 使用数组模拟栈,需要手动管理内存。

如果有其他问题,欢迎继续提问!

你可能感兴趣的:(华为od,java,javascript,c语言,C++,python)