剑指offer(5 替换空格) 题解
微信搜索【程序员画工师】关注更多Java编程技术、数据结构与算法、面试题相关内容。
题目
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则输出“We%20are%20happy.”。
思路
最简单的做法就是从头到尾扫描字符串,每次碰到空格字符的时候就进行替换。创建新的StringBuffe对象(StringBuffer是线程安全的,每一个方法都加了锁,而StringBuilder是非线程安全的,方法没有加锁,如果采用StringBuilder对象则会快一点),遍历原字符串,当为空格时,替换为"%20",当不是空格的时候,复制原来位置上的字符串,时间复杂度为o(n),由于创建了新的对象占用了内存空间,是空间换时间的方法。或者Java string的replaceAll方法即可实现替换。
上代码
public class Solution {
public String replaceSpace1(StringBuffer str) {
return str.toString().replaceAll(" ","%20");
}
public String replaceSpace2(StringBuffer str) {
int strLen = str.toString().length();
StringBuffer strReplaced = new StringBuffer();
for(int i = 0;i<strLen;i++){
if(str.charAt(i) == ' '){
strReplaced.append("%20");
}else {
strReplaced.append(str.charAt(i));
}
}
return strReplaced.toString();
}
}
剑指解法
如果不允许创建新的内存空间,只给定一个数组来进行替换的话,碰到一个空格,就加入"%20",于是可以从头到尾遍历字符串,碰到空格,首先将后面的所有字符串往后移动2个字符,这样才能空出3个字符位置插入字符“%20”,对于一个长度为n的字符串,对每个空格,需要移动后面O(n)个字符,因此包含n个空格的字符串,总的时间复杂度为O(n*n)。
思考:那有没有更优化的解法呢?
我们可以从后往前开始替换,首先遍历一遍字符串,统计出空格的个数,并由此能够计算出替换之后的字符串的长度。接着再次从后往前遍历字符串,同时设置两个索引P1和P2,P1指向原始字符串末尾,P2指向替换之后的字符串末尾。我们向前移动P1,逐个把它指向的字符复制到P2指向的位置,直到碰到第一个空格为止。然后把P1向前移动一格,在P2之前插入字符串“%20”,同时P2向前移动3格。重复此过程,直到所有的空格都已替换完。这样只需要扫描一遍,时间复杂度为O(n)。
移动示意图如下:
剑指解法C++版代码
public:
void replaceSpace(char *str,int length) {
if(str == NULL && length <= 0){
return;
}
/*original_length为字符串str的实际长度*/
int original_length = 0; //原始长度
int number_blank = 0; //空格数
int i;
while(str[i++] != '\0'){ //遍历字符串
++original_length; //长度+1
if(str[i] == ' '){
++number_blank; //遇到空格+1
}
}
/*new_length为把空格替换成'%20'之后的长度*/
int new_length = original_length + 2 * number_blank;
int index_original = original_length; //原始字符串末尾索引值
int index_new = new_length; //计算长度后的字符串末尾索引值
/*index_original指针开始向前移动,如果遇到空格,替换成'%20',否则进行复制操作*/
while(index_original >= 0 && index_new > index_original){
if(str[index_original] == ' '){
str[index_new--] = '0';
str[index_new--] = '2';
str[index_new--] = '%';
}
else{
str[index_new--] = str[index_original];
}
--index_original;
}
}
};
附剑指解法Java版代码供读者参考
public class Solution {
public String replaceSpace(StringBuffer str) {
int lengthOriginal = str.toString().length(); //原始长度
int blankNum = 0; //空格数
//计算空格数
for(int i = 0;i<lengthOriginal;i++){
if(str.charAt(i) == ' '){
blankNum ++ ;
}
}
int lengthFinal = str.toString().length() + 2 * blankNum; //替换后的字符串长度
int indexOriginal = lengthOriginal - 1;//原始字符串的末尾索引
int indexFinal = lengthFinal - 1;//替换后字符串的末尾索引
char[] array = new char[lengthFinal]; //数组
for(int i = 0;i<lengthOriginal;i++){ //复制到数组中
array[i] = str.charAt(i);
}
while(indexOriginal >= 0 && indexOriginal != indexFinal){
if(array[indexOriginal] == ' '){
array[indexFinal--] = '0';
array[indexFinal--] = '2';
array[indexFinal--] = '%';
}else{
array[indexFinal--] = array[indexOriginal];
}
indexOriginal--; // 从后先前遍历
}
String strReplaced = "";
for(char i : array){
strReplaced = strReplaced + String.valueOf(i);
}
return strReplaced;
}
}
References
[1]:《剑指offer(第二版)》 何海涛著
程序员画工师公众号,欢迎交流