嗯,這一題主要是爲了保證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;
}