题目
请实现一个函数,把字符串中的每个空格替换成“%20”。例如,输入“We are happy.”,则输出“We%20are%20happy.”。
思路
看到这个问题,我们通常的思路是从前向后遍历字符串,每遇到一个空格将空格之后的字符向后移动两位,然后将将“%20”插进去,假设字符串长度为n,有n个空格,对于每个空格,需要移动后面的字符的时间复杂度为o(n),则对于n个空格时间复杂度为o(n*n);在前面的分析中我们发现数组中很多字符都移动了多次,能不能找一个好方法来减少移动次数呐?接下来我们来看一个时间复杂度为o(n)的算法,把从前向后替换改为从后向前替换。
- 我们先遍历一遍字符串,先统计出空格的数量,并可以借此计算出替换后字符串的长度。每替换一个空格,字符串的长度加2,因此替换后的字符串的长度为原来的长度+空格数2;以题目给的样例为例“We are happy.”这个字符串在java中长度为13(java字符串末尾没有‘\0’),里面有两个空格,因此替换后的字符串长度为13+22=17;
- 我们开始从字符串的后面开始复制和替换。准备两个索引indexOfOriginal(旧字符串的最后一个字符的下标)indexOfNew(替换后的字符串的最后一个字符的下标),然后开始从后(即用indexOfOriginal递减来实现)向前遍历字符串。
- 如果indexOfOriginal指向的字符为空格时 ,则将indexOfNew所在的位置赋值为‘0’,然后将indexOfNew向前移动一个位置,将新位置赋值为’2’,继续将indexOfNew向前移动一个位置,将新位置赋值为’%’,继续将indexOfNew向前移动一个位置。此时从后向前的第一个空格替换完成;继续遍历字符串。
- 如果indexOfOriginal指向的字符不为空时,直接将该字符赋值给indexOfNew指向的位置,然后将indexOfNew向前移动一个位置。
- 重复3和4直到字符串被遍历完。
从上面分析来看,所有的字符都只需要移动一次,因此时间复杂度为o(n).
代码实现(java)
import java.util.Scanner;
/**
* @author FengTianHao
* @version 1.0
* @since 2018/11/30 11:07
*
*/
public class Test {
public String replaceSpace(StringBuffer str) {
if(str==null||str.length()==0)
{
return str.toString();
}
int numberOfBlank=0;//空格的数量
for(int i=0;i<str.length();i++)
{
if(str.charAt(i)==' ')
{
numberOfBlank++;
}
}
int indexOfOriginal=str.length()-1;//指向旧字符串的最后一个字符
int newlength=str.length()+numberOfBlank*2;//计算新字符串的长度
str.setLength(newlength);//将旧字符串的空间扩大
int indexOfNew=str.length()-1;//指向新字符换的最后一个字符
for(;indexOfOriginal>=0&&indexOfNew>indexOfOriginal;--indexOfOriginal)
{
if(str.charAt(indexOfOriginal)==' ')//当前字符为空格时
{
str.setCharAt(indexOfNew--,'0');
str.setCharAt(indexOfNew--,'2');
str.setCharAt(indexOfNew--,'%');
}
else//当前字符不为空格时
{
str.setCharAt(indexOfNew--,str.charAt(indexOfOriginal));
}
}
return str.toString();
}
public static void main(String[]args) {
StringBuffer str=new StringBuffer(" We are happy.");
System.out.println(new Test().replaceSpace(str));
}
}