题目
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
解析
思路一
很可能陷入误区,以为只要返回的字符串符合题意就可以,其实并不然。这道题其实考察的是在原址上进行字符串替换操作。所以下面的代码是错误!
str.toString().replaceAll(" ", "%20");
思路二
原址上的操作的最终目的也是改变原字符串啊,所以转变思路为另申请一个内存空间,在该空间进行字符换替换操作,待完成替换后把结果拷贝到原址上,这样也可以达到原址上字符串操作的效果,有种投机取巧的赶脚。
/**
* 常规解法,开辟一个新的空间进行处理结果,最后再copy到原空间上。
* @param str
* @return
*/
public static String replaceSpace1(StringBuffer str) {
String s = str.toString();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == ' '){
sb.append("%20");
}else {
sb.append(s.charAt(i));
}
}
str.delete(0, str.length());
str.append(sb);
return str.toString();
}
思路三
即是正规的原址操作了,观察我们的字符串后,发现替换后的字符串的总长度为原长度 + 2 * 空格数组。所以我们可以考虑扩展我们的字符串的长度,然后通过插入和移动元素来完成。
这里如果我们从头到尾进行依次处理插入,会发现每处理一次空格,后面的字符都要往后移动2格,复杂度为O(n的平方)。那有没有其他方法可以直接就确定每个字符的最终位置,从而避免每次都要移位呢?
我们从尾部处理就可以啊,你想啊,最后一个字符必然处于扩展后字符串的最后一位,所以我们直接从后处理,直接确定每个字符最终的位置。
We are happy
We%20are%20happy
观察发现,y向后的移动位数为(y之前的空格数)*2
e向后移动的位数为(e之前的空格数)* 2
所以需要先统计出空格数,然后根据当前空格数,
确定需要移动位数,空格的情况移动的位数所需的空格数就不必包含本身了。
比如倒数第一个空格向后移动的位数为它之前空格数*2,然后该位置需要替换为%, 之后依次2,0
代码如下:
public static String replaceSpace2(StringBuffer str) {
int spaceNum = 0;
for(int i = 0; i < str.length(); i++) {
if(str.charAt(i) == ' ') {
spaceNum++;
}
}
int oldLength = str.length();
str.setLength(oldLength + spaceNum * 2);
for(int i = oldLength - 1; i >= 0; i--){
if(str.charAt(i) != ' ') {
str.setCharAt(i + 2 * spaceNum, str.charAt(i));
}else {
spaceNum--;
int length = i + 2 * spaceNum;
str.setCharAt(length, '%');
str.setCharAt(length + 1, '2');
str.setCharAt(length + 2, '0');
}
}
return str.toString();
}
思路四
也就是《剑指Offer》的标准解法了。就是直接用2个尾指针就可以了,依次对号入座,简单粗暴。
/**
* 剑指Offer上的标准解法
* @param str
* @return
*/
public static String replaceSpace3(StringBuffer str) {
int spaceNum = 0;
for(int i = 0; i < str.length(); i++) {
if(str.charAt(i) == ' ') {
spaceNum++;
}
}
int oldLength = str.length();
str.setLength(oldLength + spaceNum * 2);
int newLength = str.length();
for(oldLength--, newLength--; oldLength >= 0 && oldLength < newLength; oldLength--){
if(str.charAt(oldLength) != ' ') {
str.setCharAt(newLength--, str.charAt(oldLength));
}else {
str.setCharAt(newLength--, '0');
str.setCharAt(newLength--, '2');
str.setCharAt(newLength--, '%');
}
}
return str.toString();
}
拓展
- 数组合并,数组拓展问题,都可以从尾部开始