剑指Offer 面试题4 替换空格
本文参考《剑指offer 名企面试官精讲典型编程题》面试题4。
感谢原书作者:何海涛。
题目4:请实现一个函数,把字符串中的每个空格替换成"%20"。例如:输入"hello world.",则输出"hello%20world."。
在网络编程中,如果URL参数中含有特殊字符,如空格,'#'等,可能导致服务端无法获得正确的参数值。我们需要将特殊符号转换为服务器可以识别的字符。转换规则为在'%'后面跟上ASCII码的两位十六进制。空格可以被替换为"%20",'#'可以被替换为"%23"。
时间复杂度为O(n)的解法:
可以先遍历一次字符串,统计出字符串中的空格总数,并由此计算出替换之后的字符串总长度。每替换一个空格,长度增加2。替换后的字符串长度等于原来的长度加上空格数乘以2。
准备两个指针P1,P2从后往前开始复制替换。P1指向原字符串末尾,P2指向替换之后的字符串末尾。接下来我们向前移动指针P1,逐步将它指向的字符复制到P2指向的位置,直到碰到第一个空格为止。碰到第一个空格后,P1向前移动一格,P2之前插入"%20",同时把P2向前移动3格。当P1和P2指向同一个位置,表明所有空格替换完毕。
以下为操作示意图:
注:图中阴影区域表示被移动的字符。
我以Java为编程语言实现上述思想:
package array; /** * @author WuPing * @version 2016年4月8日 上午11:05:59 */ public class ReplaceBlank { public static void replaceBlank(char strings[], int length) { // length为字符数组string的总容量 if (strings != null && length > 0) { int originalLength = 0; // 字符数组实际长度 int numberOfBlank = 0; // 字符数组中的空格数 int i = 0; while (strings[i] != '\0') { ++originalLength; if (strings[i] == ' ') ++numberOfBlank; ++i; } // newLength为把空格替换成'%20'之后的长度 int newLength = originalLength + numberOfBlank * 2; if (newLength > length) return; int indexOfOriginal = originalLength; // 字符数组起始扫描索引 int indexOfNew = newLength; // 替换空格后的字符数组起始扫描索引 while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal) { // 从后向前扫描,遇到空格则替换成'%20',否则直接复制字符 if (strings[indexOfOriginal] == ' ') { strings[indexOfNew--] = '0'; strings[indexOfNew--] = '2'; strings[indexOfNew--] = '%'; } else { strings[indexOfNew--] = strings[indexOfOriginal]; } --indexOfOriginal; } } } //空格在字符串中间 public static void Test1(int length) { char[] test1Strings = new char[length]; test1Strings[0] = 'h'; test1Strings[1] = 'e'; test1Strings[2] = 'l'; test1Strings[3] = 'l'; test1Strings[4] = 'o'; test1Strings[5] = ' '; test1Strings[6] = 'w'; test1Strings[7] = 'o'; test1Strings[8] = 'r'; test1Strings[9] = 'l'; test1Strings[10] = 'd'; test1Strings[11] = '\0'; // 模拟字符串结束符 System.out.println("Test1 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test1Strings.length; i++) { if (test1Strings[i] == '\0') { break; } System.out.print(test1Strings[i]); } System.out.println(); replaceBlank(test1Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test1Strings.length; i++) { if (test1Strings[i] == '\0') { break; } System.out.print(test1Strings[i]); } System.out.println(); } //空格在字符串开头 public static void Test2(int length) { char[] test2Strings = new char[length]; test2Strings[0] = ' '; test2Strings[1] = 'h'; test2Strings[2] = 'e'; test2Strings[3] = 'l'; test2Strings[4] = 'l'; test2Strings[5] = 'o'; test2Strings[6] = 'w'; test2Strings[7] = 'o'; test2Strings[8] = 'r'; test2Strings[9] = 'l'; test2Strings[10] = 'd'; test2Strings[11] = '\0'; // 模拟字符串结束符 System.out.println("Test2 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test2Strings.length; i++) { if (test2Strings[i] == '\0') { break; } System.out.print(test2Strings[i]); } System.out.println(); replaceBlank(test2Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test2Strings.length; i++) { if (test2Strings[i] == '\0') { break; } System.out.print(test2Strings[i]); } System.out.println(); } //空格在字符串末尾 public static void Test3(int length) { char[] test3Strings = new char[length]; test3Strings[0] = 'h'; test3Strings[1] = 'e'; test3Strings[2] = 'l'; test3Strings[3] = 'l'; test3Strings[4] = 'o'; test3Strings[5] = 'w'; test3Strings[6] = 'o'; test3Strings[7] = 'r'; test3Strings[8] = 'l'; test3Strings[9] = 'd'; test3Strings[10] = ' '; test3Strings[11] = '\0'; // 模拟字符串结束符 System.out.println("Test3 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test3Strings.length; i++) { if (test3Strings[i] == '\0') { break; } System.out.print(test3Strings[i]); } System.out.println(); replaceBlank(test3Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test3Strings.length; i++) { if (test3Strings[i] == '\0') { break; } System.out.print(test3Strings[i]); } System.out.println(); } //字符串中有连续两个空格 public static void Test4(int length) { char[] test4Strings = new char[length]; test4Strings[0] = 'h'; test4Strings[1] = 'e'; test4Strings[2] = 'l'; test4Strings[3] = 'l'; test4Strings[4] = 'o'; test4Strings[5] = ' '; test4Strings[6] = ' '; test4Strings[7] = 'w'; test4Strings[8] = 'o'; test4Strings[9] = 'r'; test4Strings[10] = 'l'; test4Strings[11] = 'd'; test4Strings[12] = '\0'; // 模拟字符串结束符 System.out.println("Test4 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test4Strings.length; i++) { if (test4Strings[i] == '\0') { break; } System.out.print(test4Strings[i]); } System.out.println(); replaceBlank(test4Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test4Strings.length; i++) { if (test4Strings[i] == '\0') { break; } System.out.print(test4Strings[i]); } System.out.println(); } //字符数组为null public static void Test5() { System.out.print("Test5 begin: "); replaceBlank(null, 0); System.out.println("passed!"); } //字符串为空串 public static void Test6(int length) { char[] test6Strings = new char[length]; test6Strings[0] = '\0'; // 模拟字符串结束符 System.out.println("Test6 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test6Strings.length; i++) { if (test6Strings[i] == '\0') { break; } System.out.print(test6Strings[i]); } System.out.println(); replaceBlank(test6Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test6Strings.length; i++) { if (test6Strings[i] == '\0') { break; } System.out.print(test6Strings[i]); } System.out.println(); } //字符串为一个空格 public static void Test7(int length) { char[] test7Strings = new char[length]; test7Strings[0] = ' '; test7Strings[1] = '\0'; // 模拟字符串结束符 System.out.println("Test7 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test7Strings.length; i++) { if (test7Strings[i] == '\0') { break; } System.out.print(test7Strings[i]); } System.out.println(); replaceBlank(test7Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test7Strings.length; i++) { if (test7Strings[i] == '\0') { break; } System.out.print(test7Strings[i]); } System.out.println(); } //字符串中没有空格 public static void Test8(int length) { char[] test8Strings = new char[length]; test8Strings[0] = 'h'; test8Strings[1] = 'e'; test8Strings[2] = 'l'; test8Strings[3] = 'l'; test8Strings[4] = 'o'; test8Strings[5] = 'w'; test8Strings[6] = 'o'; test8Strings[7] = 'r'; test8Strings[8] = 'l'; test8Strings[9] = 'd'; test8Strings[10] = '\0'; // 模拟字符串结束符 System.out.println("Test8 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test8Strings.length; i++) { if (test8Strings[i] == '\0') { break; } System.out.print(test8Strings[i]); } System.out.println(); replaceBlank(test8Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test8Strings.length; i++) { if (test8Strings[i] == '\0') { break; } System.out.print(test8Strings[i]); } System.out.println(); } //字符串中全是空格 public static void Test9(int length) { char[] test9Strings = new char[length]; test9Strings[0] = ' '; test9Strings[1] = ' '; test9Strings[2] = ' '; test9Strings[3] = ' '; test9Strings[4] = '\0'; // 模拟字符串结束符 System.out.println("Test9 begin: "); System.out.print("替换空格前的字符数组:"); for (int i = 0; i < test9Strings.length; i++) { if (test9Strings[i] == '\0') { break; } System.out.print(test9Strings[i]); } System.out.println(); replaceBlank(test9Strings, length); System.out.print("替换空格后的字符数组:"); for (int i = 0; i < test9Strings.length; i++) { if (test9Strings[i] == '\0') { break; } System.out.print(test9Strings[i]); } System.out.println(); } public static void main(String[] args) { int length = 100; Test1(length); Test2(length); Test3(length); Test4(length); Test5(); Test6(length); Test7(length); Test8(length); Test9(length); } }程序运行结果如下图: