嗯,这一题主要是为了保证encode和decode的唯一性,我面google的时候遇到过,当时面试官给的提示很简单,随便定义一个字符为分隔符,字符串之间用分隔符定义开来,如果遇到分隔符就变成两个。举个例子,如果你拿逗号来做分隔符。
那么"ab", "b,b", "d,b,ee" encode之后就会变成"ab,b,,b,d,,b,,ee,",decode也很简单,遇到单个逗号就表示一个字符串终结了开始新的字符串,遇到偶数个逗号就表示真的遇到了一个逗号。所以decode下来,就变成"ab", "b,b", "d,b,ee",就和原来encode之前是一样的了。
这个做法咋看上去是对的,当时我也是这么做的,面试官也没说啥表示通过了,通过了,过了,了.....
但实际上这种做法并不对,不完全对。举个例子,"a,","b"或者"a",",b" encode之后都会变成"a,,,b"。但是你decode的时候却没有办法区分开来。这就失去了唯一性了。同样的,连续两个空字符串也会让这种做法露出马脚。",,"。这样就会变成一个逗号的字符串。
所以我们要引入一个新的字符作为分隔符的辅助字符,譬如感叹号"!"。这样,当遇到","的时候,原本的做法是把它变成",,"。现在就变成",!"。然后遇到感叹号自己的时候就变为"!!"。这样,就不会出现因为连续逗号而形成的混乱局面。同样的,连续的感叹号也不会形成混乱局面,因为一旦出现逗号,只需要判断后面的连续感叹号的数目是奇数还是偶数,如果是偶数,那么当前的逗号肯定就是一个分隔符。后面的感叹号是下一个原字符串的感叹号所形成的。如果是奇数,那么第一个原字符是逗号翻译而成的“,!”,后面的感叹号则是原字符串的感叹号转义而成的。
根据上述描述,可以得到代码如下:
// Encodes a list of strings to a single string.
public String encode(List<String> strs) {
StringBuilder sb = new StringBuilder();
for (String str : strs) {
char[] chArr = str.toCharArray();
for (char ch : chArr) {
switch(ch) {
case ',' :
sb.append(",!");
break;
case '!' :
sb.append("!!");
break;
default:
sb.append(ch);
break;
}
}
sb.append(",");
}
return sb.toString();
}
// Decodes a single string to a list of strings.
public List<String> decode(String s) {
List<String> result = new LinkedList<String>();
StringBuilder sb = new StringBuilder();
char[] chArr = s.toCharArray();
for (int i = 0; i < chArr.length; i++) {
if (chArr[i] == ',') {
int cursor = i + 1;
while (cursor < chArr.length && chArr[cursor] == '!') {
cursor++;
}
if ((cursor - i) % 2 == 1) {
result.add(sb.toString());
sb.delete(0, sb.length());
} else {
sb.append(',');
i++;
}
for (int j = i + 1; j < cursor; j += 2) {
sb.append('!');
}
i = cursor - 1;
} else if (chArr[i] == '!') {
sb.append('!');
i++;
} else {
sb.append(chArr[i]);
}
}
return result;
}