Bootstrap

【2024年华为OD机试】 (C卷,100分)- 消消乐游戏(Java & JS & Python&C/C++)

在这里插入图片描述

一、问题描述

题目描述

游戏规则:输入一个只包含英文字母的字符串,字符串中的两个字母如果相邻且相同,就可以消除。

在字符串上反复执行消除的动作,直到无法继续消除为止,此时游戏结束。

输出最终得到的字符串长度。

输入描述

输入原始字符串 str,只能包含大小写英文字母,字母的大小写敏感,str 长度不超过100。

输出描述

输出游戏结束后,最终得到的字符串长度。

备注

输入中包含非大小写英文字母时,均为异常输入,直接返回 0。

用例

用例 1

输入:

gg

输出:

0

说明:
gg 可以直接消除,得到空串,长度为 0。

用例 2

输入:

mMbccbc

输出:

3

说明:
mMbccbc 中,可以先消除 cc
此时字符串变成 mMbbc,可以再消除 bb
此时字符串变成 mMc,此时没有相邻且相同的字符,无法继续消除。
最终得到的字符串为 mMc,长度为 3。

题目解析

这题比较容易地解法是利用栈结构。

即先创建一个栈,然后遍历输入的字符串,将每一个字符尝试压入栈,但是压入前,需要判断,栈顶元素是否和将要压入的字符相同,若不同,则压入,若相同,则字符不压入,且栈顶元素弹出。

由于这题只要遇到两两相邻相同的字符就会消除,比如 acccb,消除后就变为了 acb,因此遇到 >2 的奇数个相同相邻字符,是无法消除完的,总是会遗留一个。

注意,遍历的字符如果是非字母,则直接返回 0。

详细步骤

  1. 读取输入

    • 从标准输入读取一个字符串 str
  2. 检查输入合法性

    • 如果字符串中包含非字母字符,直接返回 0。
  3. 初始化栈

    • 创建一个空栈 stack,用于存储字符。
  4. 遍历字符串

    • 遍历字符串中的每个字符 char
      • 如果 stack 不为空且 stack 的栈顶元素与 char 相同,弹出栈顶元素。
      • 否则,将 char 压入栈中。
  5. 输出结果

    • 输出栈的长度,即最终字符串的长度。

用例解释

用例 1
  • 输入:
    • gg
  • 输出:
    • 0

解释

  • 遍历字符串 gg
    • g -> 压入栈中,栈:[g]
    • g -> 栈顶元素为 g,弹出栈顶元素,栈:[]
  • 最终栈为空,长度为 0。
用例 2
  • 输入:
    • mMbccbc
  • 输出:
    • 3

解释

  • 遍历字符串 mMbccbc
    • m -> 压入栈中,栈:[m]
    • M -> 压入栈中,栈:[m, M]
    • b -> 压入栈中,栈:[m, M, b]
    • c -> 压入栈中,栈:[m, M, b, c]
    • c -> 栈顶元素为 c,弹出栈顶元素,栈:[m, M, b]
    • b -> 栈顶元素为 b,弹出栈顶元素,栈:[m, M]
    • c -> 压入栈中,栈:[m, M, c]
  • 最终栈为 [m, M, c],长度为 3。

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

二、JavaScript算法源码

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


JavaScript 代码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline"); // 引入 readline 模块,用于读取控制台输入

// 创建 readline 接口
const rl = readline.createInterface({
  input: process.stdin,  // 输入流为标准输入
  output: process.stdout, // 输出流为标准输出
});

// 监听 'line' 事件,当用户输入一行内容时触发
rl.on("line", (line) => {
  console.log(getResult(line)); // 调用 getResult 方法处理输入,并输出结果
});

/**
 * 计算字符串中未匹配字符的数量
 * @param {string} s 输入的字符串
 * @returns {number} 未匹配字符的数量
 */
function getResult(s) {
  const stack = []; // 使用数组模拟栈

  // 遍历字符串中的每个字符
  for (let c of s) {
    // 检查字符是否为字母(A-Z 或 a-z)
    if (c < "A" || c > "z" || (c > "Z" && c < "a")) {
      return 0; // 如果字符不是字母,直接返回 0
    }

    // 如果栈不为空且当前字符与栈顶字符相同
    if (stack.length > 0 && stack.at(-1) == c) {
      stack.pop(); // 移除栈顶字符(匹配成功)
    } else {
      stack.push(c); // 将当前字符压入栈中(未匹配)
    }
  }

  return stack.length; // 返回栈中剩余的未匹配字符数量
}

代码逻辑讲解

1. 输入处理
  • 使用 readline 模块读取控制台输入。
  • 监听 'line' 事件,当用户输入一行内容时,调用 getResult 方法处理输入,并输出结果。

2. 字符匹配逻辑
  • 使用数组 stack 模拟栈的行为:
    • 栈用于存储未匹配的字符。
    • 如果当前字符与栈顶字符相同,则匹配成功,移除栈顶字符。
    • 如果当前字符与栈顶字符不同,则将当前字符压入栈中。

3. 字符有效性检查
  • 检查当前字符是否为字母(A-Za-z):
    • 如果字符不是字母,直接返回 0
    • 这是为了确保输入字符串中只包含字母。

4. 返回结果
  • 最终返回栈中剩余的未匹配字符数量:
    • 如果栈为空,说明所有字符都匹配成功。
    • 如果栈不为空,说明栈中剩余的字符未匹配。

示例验证

示例 1:s = “abba”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • stack.length = 0(所有字符匹配成功)。
示例 2:s = “abc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'c':压入栈中,栈内容:['a', 'b', 'c']
  • 结果:
    • stack.length = 3(所有字符未匹配)。
示例 3:s = “aabbcc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'b':压入栈中,栈内容:['b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'c':压入栈中,栈内容:['c']
    • 字符 'c':与栈顶字符 'c' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • stack.length = 0(所有字符匹配成功)。

总结

  • 功能:统计字符串中未匹配字符的数量。
  • 核心逻辑
    1. 使用栈来匹配相邻的相同字符。
    2. 如果字符匹配成功,移除栈顶字符;否则,将字符压入栈中。
    3. 最终返回栈中剩余的未匹配字符数量。
  • 适用场景:需要检查字符串中是否存在未匹配的字符。
  • 注意事项
    • 输入字符串只能包含字母(A-Za-z)。
    • 如果字符串为空,结果为 0

如果有其他问题,欢迎随时提问!

三、Java算法源码

以下是 Java 代码 的详细中文注释和逻辑讲解:


Java 代码

import java.util.LinkedList; // 引入 LinkedList 类,用于实现栈的功能
import java.util.Scanner;    // 引入 Scanner 类,用于读取用户输入

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in); // 创建 Scanner 对象,用于读取控制台输入
    System.out.println(getResult(sc.nextLine())); // 读取一行输入并调用 getResult 方法,输出结果
  }

  /**
   * 计算字符串中未匹配字符的数量
   * @param s 输入的字符串
   * @return 未匹配字符的数量
   */
  public static int getResult(String s) {
    LinkedList<Character> stack = new LinkedList<>(); // 使用 LinkedList 模拟栈

    // 遍历字符串中的每个字符
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i); // 获取当前字符

      // 检查字符是否为字母(A-Z 或 a-z)
      if (c < 'A' || c > 'z' || (c > 'Z' && c < 'a')) {
        return 0; // 如果字符不是字母,直接返回 0
      }

      // 如果栈不为空且当前字符与栈顶字符相同
      if (stack.size() > 0 && c == stack.getLast()) {
        stack.removeLast(); // 移除栈顶字符(匹配成功)
      } else {
        stack.addLast(c); // 将当前字符压入栈中(未匹配)
      }
    }

    return stack.size(); // 返回栈中剩余的未匹配字符数量
  }
}

代码逻辑讲解

1. 输入处理
  • 使用 Scanner 类从控制台读取一行输入,并将其作为参数传递给 getResult 方法。

2. 字符匹配逻辑
  • 使用 LinkedList 模拟栈的行为:
    • 栈用于存储未匹配的字符。
    • 如果当前字符与栈顶字符相同,则匹配成功,移除栈顶字符。
    • 如果当前字符与栈顶字符不同,则将当前字符压入栈中。

3. 字符有效性检查
  • 检查当前字符是否为字母(A-Za-z):
    • 如果字符不是字母,直接返回 0
    • 这是为了确保输入字符串中只包含字母。

4. 返回结果
  • 最终返回栈中剩余的未匹配字符数量:
    • 如果栈为空,说明所有字符都匹配成功。
    • 如果栈不为空,说明栈中剩余的字符未匹配。

示例验证

示例 1:s = “abba”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • stack.size() = 0(所有字符匹配成功)。
示例 2:s = “abc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'c':压入栈中,栈内容:['a', 'b', 'c']
  • 结果:
    • stack.size() = 3(所有字符未匹配)。
示例 3:s = “aabbcc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'b':压入栈中,栈内容:['b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'c':压入栈中,栈内容:['c']
    • 字符 'c':与栈顶字符 'c' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • stack.size() = 0(所有字符匹配成功)。

总结

  • 功能:统计字符串中未匹配字符的数量。
  • 核心逻辑
    1. 使用栈来匹配相邻的相同字符。
    2. 如果字符匹配成功,移除栈顶字符;否则,将字符压入栈中。
    3. 最终返回栈中剩余的未匹配字符数量。
  • 适用场景:需要检查字符串中是否存在未匹配的字符。
  • 注意事项
    • 输入字符串只能包含字母(A-Za-z)。
    • 如果字符串为空,结果为 0

如果有其他问题,欢迎随时提问!

四、Python算法源码

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


Python 代码

# 输入获取
s = input()  # 从控制台读取一行输入,存储到变量 s 中

# 算法入口
def getResult():
    stack = []  # 使用列表模拟栈

    # 遍历字符串中的每个字符
    for c in s:
        # 检查字符是否为字母(A-Z 或 a-z)
        if c < 'A' or c > 'z' or ('Z' < c < 'a'):
            return 0  # 如果字符不是字母,直接返回 0

        # 如果栈不为空且当前字符与栈顶字符相同
        if len(stack) > 0 and stack[-1] == c:
            stack.pop()  # 移除栈顶字符(匹配成功)
        else:
            stack.append(c)  # 将当前字符压入栈中(未匹配)

    return len(stack)  # 返回栈中剩余的未匹配字符数量

# 算法调用
print(getResult())  # 调用 getResult 方法并输出结果

代码逻辑讲解

1. 输入处理
  • 使用 input() 函数从控制台读取一行输入,并将其存储到变量 s 中。

2. 字符匹配逻辑
  • 使用列表 stack 模拟栈的行为:
    • 栈用于存储未匹配的字符。
    • 如果当前字符与栈顶字符相同,则匹配成功,移除栈顶字符。
    • 如果当前字符与栈顶字符不同,则将当前字符压入栈中。

3. 字符有效性检查
  • 检查当前字符是否为字母(A-Za-z):
    • 如果字符不是字母,直接返回 0
    • 这是为了确保输入字符串中只包含字母。

4. 返回结果
  • 最终返回栈中剩余的未匹配字符数量:
    • 如果栈为空,说明所有字符都匹配成功。
    • 如果栈不为空,说明栈中剩余的字符未匹配。

示例验证

示例 1:s = “abba”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • len(stack) = 0(所有字符匹配成功)。
示例 2:s = “abc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'c':压入栈中,栈内容:['a', 'b', 'c']
  • 结果:
    • len(stack) = 3(所有字符未匹配)。
示例 3:s = “aabbcc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'b':压入栈中,栈内容:['b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'c':压入栈中,栈内容:['c']
    • 字符 'c':与栈顶字符 'c' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • len(stack) = 0(所有字符匹配成功)。

总结

  • 功能:统计字符串中未匹配字符的数量。
  • 核心逻辑
    1. 使用栈来匹配相邻的相同字符。
    2. 如果字符匹配成功,移除栈顶字符;否则,将字符压入栈中。
    3. 最终返回栈中剩余的未匹配字符数量。
  • 适用场景:需要检查字符串中是否存在未匹配的字符。
  • 注意事项
    • 输入字符串只能包含字母(A-Za-z)。
    • 如果字符串为空,结果为 0

如果有其他问题,欢迎随时提问!

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

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


C++ 代码

#include <iostream>
#include <stack>
using namespace std;

// 算法入口
int getResult(string s) {
    stack<char> st; // 使用栈来存储未匹配的字符

    // 遍历字符串中的每个字符
    for (char c : s) {
        // 检查字符是否为字母(A-Z 或 a-z)
        if (c < 'A' || c > 'z' || (c > 'Z' && c < 'a')) {
            return 0; // 如果字符不是字母,直接返回 0
        }

        // 如果栈不为空且当前字符与栈顶字符相同
        if (!st.empty() && st.top() == c) {
            st.pop(); // 移除栈顶字符(匹配成功)
        } else {
            st.push(c); // 将当前字符压入栈中(未匹配)
        }
    }

    return st.size(); // 返回栈中剩余的未匹配字符数量
}

int main() {
    string s;
    cin >> s; // 从控制台读取输入字符串
    cout << getResult(s) << endl; // 调用 getResult 方法并输出结果
    return 0;
}

C 语言代码

#include <stdio.h>
#include <string.h>

#define MAX_SIZE 1000 // 定义栈的最大容量

// 算法入口
int getResult(char* s) {
    char stack[MAX_SIZE]; // 使用数组模拟栈
    int top = -1; // 栈顶指针,初始化为 -1 表示栈为空

    // 遍历字符串中的每个字符
    for (int i = 0; s[i] != '\0'; i++) {
        char c = s[i];

        // 检查字符是否为字母(A-Z 或 a-z)
        if (c < 'A' || c > 'z' || (c > 'Z' && c < 'a')) {
            return 0; // 如果字符不是字母,直接返回 0
        }

        // 如果栈不为空且当前字符与栈顶字符相同
        if (top >= 0 && stack[top] == c) {
            top--; // 移除栈顶字符(匹配成功)
        } else {
            stack[++top] = c; // 将当前字符压入栈中(未匹配)
        }
    }

    return top + 1; // 返回栈中剩余的未匹配字符数量
}

int main() {
    char s[MAX_SIZE];
    scanf("%s", s); // 从控制台读取输入字符串
    printf("%d\n", getResult(s)); // 调用 getResult 方法并输出结果
    return 0;
}

代码逻辑讲解

1. 输入处理
  • C++:使用 cin 从控制台读取输入字符串。
  • C 语言:使用 scanf 从控制台读取输入字符串。

2. 字符匹配逻辑
  • 使用栈来存储未匹配的字符:
    • 如果当前字符与栈顶字符相同,则匹配成功,移除栈顶字符。
    • 如果当前字符与栈顶字符不同,则将当前字符压入栈中。

3. 字符有效性检查
  • 检查当前字符是否为字母(A-Za-z):
    • 如果字符不是字母,直接返回 0
    • 这是为了确保输入字符串中只包含字母。

4. 返回结果
  • 最终返回栈中剩余的未匹配字符数量:
    • 如果栈为空,说明所有字符都匹配成功。
    • 如果栈不为空,说明栈中剩余的字符未匹配。

示例验证

示例 1:s = “abba”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • stack.size() = 0(所有字符匹配成功)。
示例 2:s = “abc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'b':压入栈中,栈内容:['a', 'b']
    • 字符 'c':压入栈中,栈内容:['a', 'b', 'c']
  • 结果:
    • stack.size() = 3(所有字符未匹配)。
示例 3:s = “aabbcc”
  • 遍历过程:
    • 字符 'a':压入栈中,栈内容:['a']
    • 字符 'a':与栈顶字符 'a' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'b':压入栈中,栈内容:['b']
    • 字符 'b':与栈顶字符 'b' 匹配,移除栈顶字符,栈内容:[]
    • 字符 'c':压入栈中,栈内容:['c']
    • 字符 'c':与栈顶字符 'c' 匹配,移除栈顶字符,栈内容:[]
  • 结果:
    • stack.size() = 0(所有字符匹配成功)。

总结

  • 功能:统计字符串中未匹配字符的数量。
  • 核心逻辑
    1. 使用栈来匹配相邻的相同字符。
    2. 如果字符匹配成功,移除栈顶字符;否则,将字符压入栈中。
    3. 最终返回栈中剩余的未匹配字符数量。
  • 适用场景:需要检查字符串中是否存在未匹配的字符。
  • 注意事项
    • 输入字符串只能包含字母(A-Za-z)。
    • 如果字符串为空,结果为 0

如果有其他问题,欢迎随时提问!

;