第31题 不同整数的计数问题 | 豆包MarsCode AI刷题

93 阅读5分钟

题目

问题描述

小R有一个字符串 word,该字符串由数字和小写英文字母组成。小R想用空格替换每一个不是数字的字符。然后,他希望统计在替换后剩下的整数中,不同整数的数目。

例如,给定字符串 "a123bc34d8ef34",替换后形成的字符串是 " 123 34 8 34",剩下的整数是 "123""34""8" 和 "34"。不同的整数有三个,即 "123""34" 和 "8"

注意,只有当两个整数的不含前导零的十进制表示不同,才认为它们是不同的整数。


测试样例

样例1:

输入:word = "a123bc34d8ef34"
输出:3

样例2:

输入:word = "t1234c23456"
输出:2

样例3:

输入:word = "a1b01c001d4"
输出:2

题目分析

这道题的目标是从一个包含字母和数字的字符串中提取所有整数,并统计这些整数的不同个数。具体要求如下:

  1. 替换掉字符串中所有不是数字的字符,数字之间用空格分隔,形成连续的整数块。
  2. 去除每个整数的前导零,以确保相同的数字表示(例如 0011)被视为相同的整数。
  3. 返回不同整数的总数。
关键点
  1. 整数的提取:提取数字字符形成完整的数字块。
  2. 前导零的处理:需要对每个数字去掉多余的前导零,确保一致性。
  3. 唯一性的判断:利用数据结构(如哈希集合 unordered_set)有效存储和去重。

解题思路

思路拆解
  1. 遍历字符串:
    • 对于每个字符:
      • 如果是数字,累积到当前数字块中。
      • 如果是非数字,说明当前数字块结束,需要将其存储并处理。
  2. 处理数字块:
    • 去除前导零(例如将 "001" 转换为 "1")。
    • 存入哈希集合中,用于自动去重。
  3. 遍历结束后:
    • 如果最后一个数字块未处理(因为字符串可能以数字结尾),需要将其存入集合。
  4. 统计集合中元素的个数并返回。
代码实现

以下是完整的 C++ 实现代码:

#include <iostream>
#include <string>
#include <unordered_set> // 用于存储唯一的整数
using namespace std;

int solution(string word) {
    unordered_set<string> uniqueIntegers; // 用于存储不含前导零的唯一整数
    string currentNum = "";              // 用于累积当前解析到的数字

    // 遍历字符串中的每个字符
    for (char ch : word) {
        if (isdigit(ch)) {
            currentNum += ch; // 如果是数字,追加到当前数字块
        } else {
            if (!currentNum.empty()) {
                // 去掉前导零
                while (currentNum.size() > 1 && currentNum[0] == '0') {
                    currentNum.erase(0, 1);
                }
                uniqueIntegers.insert(currentNum); // 将数字加入集合
                currentNum = ""; // 重置当前数字块
            }
        }
    }

    // 处理字符串结束后剩余的数字块
    if (!currentNum.empty()) {
        while (currentNum.size() > 1 && currentNum[0] == '0') {
            currentNum.erase(0, 1);
        }
        uniqueIntegers.insert(currentNum);
    }

    return uniqueIntegers.size(); // 返回集合的大小,即不同整数的个数
}

int main() {
    cout << (solution("a123bc34d8ef34") == 3) << endl; // 测试样例1
    cout << (solution("t1234c23456") == 2) << endl;   // 测试样例2
    cout << (solution("a1b01c001d4") == 2) << endl;   // 测试样例3

    return 0;
}

代码解析

主要逻辑
  1. 遍历字符串

    • 遇到数字时,将其累积到 currentNum 中,形成一个数字块。
    • 遇到非数字时,说明数字块结束,需要将 currentNum 处理后存入集合,同时清空 currentNum
  2. 去除前导零

    • 使用 while 循环删除数字字符串的前导零,确保例如 "001""1" 被认为是相同的数字。
  3. 存储唯一值

    • 使用哈希集合(unordered_set)自动处理数字去重问题。
  4. 处理字符串结束后的剩余数字块

    • 若字符串以数字结尾,遍历结束时仍会有未处理的 currentNum,需额外加入集合。
  5. 统计结果

    • 集合的大小即为不同整数的数量。
边界情况
  • 输入为空字符串 ""
    • 无任何数字块,结果为 0
  • 输入仅包含非数字字符(如 "abc"):
    • 无任何数字块,结果为 0
  • 输入仅包含数字字符(如 "00123"):
    • 直接去掉前导零,结果为 1
  • 输入包含多个零块(如 "a00b01c001d"):
    • 去除前导零后,每个数字块归一化为同一个值,结果为 1

样例分析

样例 1

输入:

"a123bc34d8ef34"

解析:

  • 替换非数字字符后为:" 123 34 8 34 "
  • 提取的数字块为:12334834
  • 不同整数为:123348(重复的 34 只计一次)。
  • 输出:3
样例 2

输入:

"t1234c23456"

解析:

  • 替换非数字字符后为:" 1234 23456 "
  • 提取的数字块为:123423456
  • 不同整数为:123423456
  • 输出:2
样例 3

输入:

"a1b01c001d4"

解析:

  • 替换非数字字符后为:" 1 01 001 4 "
  • 提取的数字块为:1010014
  • 去除前导零后为:14
  • 输出:2

复杂度分析

  1. 时间复杂度

    • 遍历字符串一次,时间复杂度为 ( O(n) ),其中 ( n ) 是字符串的长度。
    • 每个数字块去掉前导零的操作最多 ( O(m) ),总长度 ( m \leq n ),均摊复杂度为 ( O(n) )。
    • 插入集合操作的均摊复杂度为 ( O(1) ),总共插入的次数为数字块的数量。
    • 总体时间复杂度为 ( O(n) )。
  2. 空间复杂度

    • 使用了集合存储数字块,空间复杂度为 ( O(k) ),其中 ( k ) 是不同数字的数量。

总结

本题通过字符处理、前导零消除和哈希集合去重的方式,构造出高效、简洁的解决方案。整体逻辑清晰,代码易于理解,时间和空间复杂度均适合大规模输入,是一类典型的字符串与数字处理问题。