题目
问题描述
小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
题目分析
这道题的目标是从一个包含字母和数字的字符串中提取所有整数,并统计这些整数的不同个数。具体要求如下:
- 替换掉字符串中所有不是数字的字符,数字之间用空格分隔,形成连续的整数块。
- 去除每个整数的前导零,以确保相同的数字表示(例如
001和1)被视为相同的整数。 - 返回不同整数的总数。
关键点
- 整数的提取:提取数字字符形成完整的数字块。
- 前导零的处理:需要对每个数字去掉多余的前导零,确保一致性。
- 唯一性的判断:利用数据结构(如哈希集合
unordered_set)有效存储和去重。
解题思路
思路拆解
- 遍历字符串:
- 对于每个字符:
- 如果是数字,累积到当前数字块中。
- 如果是非数字,说明当前数字块结束,需要将其存储并处理。
- 对于每个字符:
- 处理数字块:
- 去除前导零(例如将
"001"转换为"1")。 - 存入哈希集合中,用于自动去重。
- 去除前导零(例如将
- 遍历结束后:
- 如果最后一个数字块未处理(因为字符串可能以数字结尾),需要将其存入集合。
- 统计集合中元素的个数并返回。
代码实现
以下是完整的 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;
}
代码解析
主要逻辑
-
遍历字符串:
- 遇到数字时,将其累积到
currentNum中,形成一个数字块。 - 遇到非数字时,说明数字块结束,需要将
currentNum处理后存入集合,同时清空currentNum。
- 遇到数字时,将其累积到
-
去除前导零:
- 使用
while循环删除数字字符串的前导零,确保例如"001"和"1"被认为是相同的数字。
- 使用
-
存储唯一值:
- 使用哈希集合(
unordered_set)自动处理数字去重问题。
- 使用哈希集合(
-
处理字符串结束后的剩余数字块:
- 若字符串以数字结尾,遍历结束时仍会有未处理的
currentNum,需额外加入集合。
- 若字符串以数字结尾,遍历结束时仍会有未处理的
-
统计结果:
- 集合的大小即为不同整数的数量。
边界情况
- 输入为空字符串
"":- 无任何数字块,结果为
0。
- 无任何数字块,结果为
- 输入仅包含非数字字符(如
"abc"):- 无任何数字块,结果为
0。
- 无任何数字块,结果为
- 输入仅包含数字字符(如
"00123"):- 直接去掉前导零,结果为
1。
- 直接去掉前导零,结果为
- 输入包含多个零块(如
"a00b01c001d"):- 去除前导零后,每个数字块归一化为同一个值,结果为
1。
- 去除前导零后,每个数字块归一化为同一个值,结果为
样例分析
样例 1
输入:
"a123bc34d8ef34"
解析:
- 替换非数字字符后为:
" 123 34 8 34 " - 提取的数字块为:
123、34、8、34 - 不同整数为:
123、34、8(重复的34只计一次)。 - 输出:
3
样例 2
输入:
"t1234c23456"
解析:
- 替换非数字字符后为:
" 1234 23456 " - 提取的数字块为:
1234、23456 - 不同整数为:
1234和23456。 - 输出:
2
样例 3
输入:
"a1b01c001d4"
解析:
- 替换非数字字符后为:
" 1 01 001 4 " - 提取的数字块为:
1、01、001、4 - 去除前导零后为:
1和4。 - 输出:
2
复杂度分析
-
时间复杂度:
- 遍历字符串一次,时间复杂度为 ( O(n) ),其中 ( n ) 是字符串的长度。
- 每个数字块去掉前导零的操作最多 ( O(m) ),总长度 ( m \leq n ),均摊复杂度为 ( O(n) )。
- 插入集合操作的均摊复杂度为 ( O(1) ),总共插入的次数为数字块的数量。
- 总体时间复杂度为 ( O(n) )。
-
空间复杂度:
- 使用了集合存储数字块,空间复杂度为 ( O(k) ),其中 ( k ) 是不同数字的数量。
总结
本题通过字符处理、前导零消除和哈希集合去重的方式,构造出高效、简洁的解决方案。整体逻辑清晰,代码易于理解,时间和空间复杂度均适合大规模输入,是一类典型的字符串与数字处理问题。