题目
将字符串中每个空格替换成 "%20"
网络编程中,如果URL参数中含有特殊字符,如空格,"#"等,可能导致服务器端无法获得正确的参数。需要将这些特殊符号转换成服务器可以识别的字符串,转换规则:'%'后面跟上ACSII码的两位十六进制的表示
空格 ACSII码是32,十六进制 0x20,转换为 '%20'
# ACSII码是35,十六进制 0x23,转换为 '%23'
方案一:使用字符串拼接
原理
逐个复制字符串的字符信息,遇空格替换
步骤
- 定义一个新的字符串变量信息
- 循环遍历目标字符串,遇到空格替换
private static String replaceBlank(String originStr) {
if (Objects.isNull(originStr) || originStr.length() == 0) {
return null;
}
StringBuilder builder = new StringBuilder();
int length = originStr.length();
for (int index = 0; index < length; index++) {
Character character = originStr.charAt(index);
if (!Objects.equals(character,' ')){
builder.append(character);
}else {
builder.append("%").append("20");
}
}
return builder.toString();
}
优缺点
优点:方案设计简单,时间复杂度为O(n) 缺点: StringBuilder 内部是一个可变长度数组,在拼接过程中多次扩容,对原有字节数据信息复制,对内存扩容,释放,效率降低
方案二:定义固定大小字符数组转换
原理
根据需要替换的空格数量,定义一个长度恰好的字节数组,按照原字符串进行字符复制,遇空格替换
步骤
- 根据原有字符串查询空格数量 n
- 定义新的字节数组 长度 = 原有字符串长度 + 2*n
- 循环原始字符串字节信息,遇空格替换
private static String replaceBlankUseArray(String originStr) {
if (Objects.isNull(originStr) || originStr.length() == 0) {
return null;
}
int originLength = originStr.length();
int blankCount = 0;
for (int index = 0; index < originLength; index++) {
Character indexCharacter = originStr.charAt(index);
if (Objects.equals(indexCharacter, ' ')) {
blankCount++;
}
}
int newLength = originLength + blankCount * 2;
char[] newStrArray = new char[newLength];
int newStrStartIndex = 0;
for (int index = 0; index < originLength; index++) {
char indexCharacter = originStr.charAt(index);
if (indexCharacter != ' ') {
newStrArray[newStrStartIndex] = indexCharacter;
} else {
newStrArray[newStrStartIndex] = '%';
newStrArray[++newStrStartIndex] = '2';
newStrArray[++newStrStartIndex] = '0';
}
//新数组复制完之后,指向下一个需要处理的位置
newStrStartIndex++;
}
return new String(newStrArray);
}
优缺点
优点:提前定义好需要的字节数组长度,避免后续扩容
题目变形
现有字符数组,从头开始存储字符,遇到NULL时结束。要求:在原有数组上操作,将空格替换成 "%20"
题目分析
| w | h | o | a | r | e | y | o | u | NULL | NULL |
|---|
- 数组中存储连续字符信息
- 连续字符下一位是NULL时,表示连续字符终结
- 要在原有的字符数组进行替换操作,不能新定义存储对象
- 需要考虑无NULL对象情况,即连续字符的最后一位数据就是数组的最后一位数据
方案一:从始到终替换
原理
定义原有数组开始角标P,由P往后遍历,遇非空格字符不处理,遇空字符时,其后所有字符信息往后移动两位,填充'%20'
步骤
- 从字符数组头部开始,逐个查询每个字节信息
- 遇到空字串时,将空字串后面的数据往后移动两位
- 对空字串进行替换
- 循环角标为数组最大长度-1或角标对应数据为NULL时结束
注意 需要判断数组长度是否能够容纳替换后的数据
private static Character[] replaceArrayBlank(Character[] targetCharacters) {
if (Objects.isNull(targetCharacters) || targetCharacters.length == 0) {
return null;
}
int originStrLength = 0;
//统计空格数量
int blankCount = 0;
for (Character targetCharacter : targetCharacters) {
if (Objects.isNull(targetCharacter)) {
break;
}
originStrLength++;
if (Objects.equals(targetCharacter, ' ')) {
blankCount++;
}
}
int targetLength = originStrLength + 2 * blankCount;
//说明无空格
if (targetLength == originStrLength) {
return targetCharacters;
}
//原始数组不能进行完成替换
if (targetLength > targetCharacters.length) {
return null;
}
//已经处理的空格数量
int handleCount = 0;
for (int index = 0; index < targetLength; index++) {
//如果已经处理的空格数量与统计的空格数量一致,已经不需要进行处理
if (handleCount == blankCount) {
break;
}
Character character = targetCharacters[index];
if (Objects.isNull(character)) {
break;
}
if (!Objects.equals(character, ' ')) {
continue;
}
//不为空字符最后位置
int originEndIndex = originStrLength + handleCount * 2 - 1;
//向后移动两位
for (int i = originEndIndex; i > index; i--) {
targetCharacters[i + 2] = targetCharacters[i];
}
targetCharacters[index] = '%';
targetCharacters[++index] = '2';
targetCharacters[++index] = '0';
handleCount ++ ;
}
return targetCharacters;
}
缺点
- 如果有多个空格,部分字符需要进行多次移动
由终到始进行替换
原理
对数组不为空数据进行由终到始循环,遇到不为空格数据,拷贝到相应位置,遇到空格数据,相应位置填充"%20"
步骤
- 定义两个指向角标信息,一个指向原数组最后一个字节位置P1,一个指向转换后最后一个角标位置P2
- 对P1循环,遇字符,复制到P2指向位置,遇空格,P2填充 '%20'信息
- P1,P2重合,表示空格已经替换完毕
private static Character[] endToStartRepalce(Character[] targetCharacters){
if (Objects.isNull(targetCharacters) || targetCharacters.length == 0) {
return null;
}
int originStrLength = 0;
//统计空格数量
int blankCount = 0;
for (Character targetCharacter : targetCharacters) {
if (Objects.isNull(targetCharacter)) {
break;
}
originStrLength++;
if (Objects.equals(targetCharacter, ' ')) {
blankCount++;
}
}
int targetLength = originStrLength + 2 * blankCount;
//说明无空格
if (targetLength == originStrLength) {
return targetCharacters;
}
int targetEndIndex = targetLength - 1;
for (int index = originStrLength - 1; index >= 0 && index < targetEndIndex ; index--) {
Character character = targetCharacters[index];
if (!Objects.equals(character,' ')){
targetCharacters[targetEndIndex] = character;
}else {
targetCharacters[targetEndIndex] = '0';
targetCharacters[--targetEndIndex] = '2';
targetCharacters[--targetEndIndex] = '%';
}
targetEndIndex --;
}
return targetCharacters;
}
优点
- 避免字符重复复制