给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。
输入一个字符串 s,s 仅包含小写字母和数字字符。
打印一个新的字符串,其中每个数字字符都被替换为了number
a1b2c3
anumberbnumbercnumber
数据范围:
1 <= s.length < 10000。
思路:
如果想把这道题目做到极致,就不要只用额外的辅助空间了! (不过使用Java刷题的录友,一定要使用辅助空间,因为Java里的string不能修改)
首先扩充数组到每个数字字符替换成 "number" 之后的大小。
例如 字符串 "a5b" 的长度为3,那么 将 数字字符变成字符串 "number" 之后的字符串为 "anumberb" 长度为 8。
如图:
然后从后向前替换数字字符,也就是双指针法,过程如下:i指向新长度的末尾,j指向旧长度的末尾。
有同学问了,为什么要从后向前填充,从前向后填充不行么?
从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素整体向后移动。
其实很多数组填充类的问题,其做法都是先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
这么做有两个好处:
?代码如下:
#include<iostream>
using namespace std;
int main()
{
string s;
int count = 0;//统计字符串中的数字的个数
while (cin >> s)
{
for (int i = 0; i < s.size(); i++)
{
if (s[i] >= '0' && s[i] <= '9') { count++; }
}
}
int oldlen = s.size();
s.resize(s.size() + 5 * count);//扩充字符串的大小,以便能够容下count个number
int newlen = s.size();
for (int i = oldlen-1, j = newlen - 1; i < j; i--,j--)
{
if (s[i] > '9' || s[i] < '0') //从后向前将非数字字符直接移到后面
{
s[j] = s[i];
continue;
}
else//将数字字符转换为number,记得将右指针往前移5位
{
s[j] = 'r',s[j-1]='e',s[j-2]='b',s[j-3]='m',s[j-4]='u',s[j-5]='n';
j -= 5;
}
}
cout << s << endl;
return 0;
}