题目描述
给你一个字符串 word ,该字符串由数字和小写英文字母组成。
请你用空格替换每个不是数字的字符。例如,“a123bc34d8ef34” 将会变成 " 123 34 8 34" 。注意,剩下的这些整数为(相邻彼此至少有一个空格隔开):“123”、“34”、“8” 和 “34” 。
返回对 word 完成替换后形成的 不同 整数的数目。
只有当两个整数的 不含前导零 的十进制表示不同, 才认为这两个整数也不同。示例 1:
输入:word = “a123bc34d8ef34”
输出:3
解释:不同的整数有 “123”、“34” 和 “8” 。注意,“34” 只计数一次。示例 2:
输入:word = “leet1234code234”
输出:2示例 3:
输入:word = “a1b01c001”
输出:1
解释:“1”、“01” 和 “001” 视为同一个整数的十进制表示,因为在比较十进制值时会忽略前导零的存在。提示:
1 <= word.length <= 1000
word 由数字和小写英文字母组成
方法一:模拟,错误
思路:
- 遍历 word ,使用 atoi 函数 将整数字符串转换为 int型,再放入 set 集合(有序、不重复),最后返回 set 内的元素个数。
情况
- 通过测试点 82 / 85;
错误原因
- 最后几个测试点的数值太大,在 set 里面会溢出,全部变为 -1 ;
收获
- 学会了 string 的相关用法:
- 向 string 类型添加字符char : s += char;
- 将 string 清空:使用函数 string.clear();
- 将 string 转换为 int 型:num = atoi(s.c_str());
- 学会了 set 的相关用法:
- set < int > nums; 【有序、不重复的迭代器】
- 向 set 添加元素 : nums.insert();
class Solution {
public:
int numDifferentIntegers(string word) {
int ans = 0;
string s;
set<int> nums;
for(auto& w : word){
// 如果当前字符不是数字,且s中已经保存了数字
if(!isdigit(w) && s.size()!=0){
// 将字符串转换为整数
int num = atoi(s.c_str());
nums.insert(num);
s.clear();
}
else if(isdigit(w)){
s += w;
}
}
// 最后一个数字字符串需要额外考虑
if(s.size()){
int num = atoi(s.c_str());
nums.insert(num);
}
return nums.size();
}
};
方法二:方法一的基础上做了改进
思路:
- 由于方法一的错误在于 set 无法存储太大的 int 型数字,那么我就「保留整数字符串」,直接存入 set 。
但是在存入之前,需要「去除整数字符串的前导零」。
在这里我定义了一个 trim 函数,指针 p 用来指向第一个非 0 的元素,此时我们就找到了需要替换的起始位置,通过 字符串长度和起始位置 相减,就得到了跨越的长度。
因此,最终得到了存入 set 的字符串。情况
- 通过;
收获
- 学会了 string 的相关用法:
- 向 string 类型替换字符char : s.substr(替换的起始位置,跨越的长度);
时间复杂度:O(n),其中 n 是 word 的长度;
空间复杂度:O(n),其中 n 是哈希表需要占用的空间。
class Solution {
public:
// 去除字符串的前导零
string trim(string str){
int p = 0; // 指向第一个非0元素
for(auto& c : str){
if(c == '0') p ++;
else break;
}
return str.substr(p, str.size() - p);
}
int numDifferentIntegers(string word) {
int ans = 0;
string s;
set<string> nums;
for(auto& w : word){
// 如果当前字符不是数字,且s中已经保存了数字
if(!isdigit(w) && s.size()!=0){
nums.insert(trim(s));
s.clear();
}
else if(isdigit(w)){
s += w;
}
}
// 最后一个数字字符串需要额外考虑
if(s.size()){
nums.insert(trim(s));
}
return nums.size();
}
};
方法三:方法二的优化,双指针
思路:
- 总体思路和方法二一样,不同的是它的代码比较简洁。直接使用双指针 i 和 j,「一次性」就把整数字符串找到,而我方法二的做法还使用了一个 字符串 s 来保存整数字符串,进而去除其前导 0 。
因此方法三的空间使用率会更低一些。情况
- 通过;
收获
- 代码简化;
时间复杂度:O(n),其中 n 是 word 的长度;
空间复杂度:O(n),其中 n 是哈希表需要占用的空间。
class Solution {
public:
int numDifferentIntegers(string word) {
set<string> nums;
int n = word.size();
for(int i=0; i<n; i++){
if(isdigit(word[i])){
// eg:000123a
// j指向a, i指向1
int j = i;
while(isdigit(word[j]) && j<n) j++;
while(i < j && word[i] == '0') i++;
nums.insert(word.substr(i, j-i));
i = j;
}
}
return nums.size();
}
};