[LintCode] Strings Serialization

Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings.

Please implement encode and decode

Example

Given strs = ["lint","code","love","you"]
string encoded_string = encode(strs)

return `["lint","code","love","you"]` when you call decode(encoded_string)

Solution 1. Application of escape sequence 

A straightforward idea is to add ";" between two strings as the divide symbol. But the problem here is, 

what about if the input strings contain ";" already? How do we distinguish between the divide symbol ";"

and the ";" that are part of the input strings? 

Consider how escape sequence works. represents the start of an escape sequence, like is a newline 

character. Since is already reserved as the start of any escape sequence, \ is used to represent the 

backslash literal. We can simply borrow this idea and use it in this problem.

Let's define : as the start of escape sequence, so :; is our divide symbol now. 

Encode:  Replace all : with :: in each string, so :: represents the original : literal;

       Connect each string with divide symbol :;

Decode: Scan from left to right until a : is met.

      If the next character is ;, it means we have a :; divide symbol; 

      If not, since we've already replaced all : with :: in encoding, so

      we know that we just saw a : literal.

 1 public class Solution {
 2     public String encode(List<String> strs) {
 3         if(strs == null){
 4             return null;
 5         }
 6         if(strs.size() == 0){
 7             return ":;";
 8         }
 9         StringBuffer sb = new StringBuffer();
10         for(String s : strs){
11             String newStr = s.replaceAll(":", "::");
12             sb.append(newStr);
13             sb.append(":;");
14         }
15         return sb.toString();
16     }
17     public List<String> decode(String str) {
18         if(str == null){
19             return null;
20         }
21         List<String> strs = new ArrayList<String>();
22         int idx = 0;
23         StringBuffer sb = new StringBuffer();        
24         while(idx < str.length()){
25             if(str.charAt(idx) != ':'){
26                 sb.append(str.charAt(idx));
27                 idx++;
28             }
29             else if(str.charAt(idx + 1) == ';'){
30                 strs.add(sb.toString());
31                 idx += 2;
32                 sb = new StringBuffer();
33             }
34             else{
35                 sb.append(":");
36                 idx += 2;
37             }
38         }
39         return strs;
40     }
41 }

Solution 2. Attach each string's length as a prefix 

Encode: add String.valueOf(str.length()) + '$' as a prefix to each string; '$' is the divide symbol between each string's length and 

    the string itself.

Q: Can we add each string's length as a suffix?  

A: No, we can't. If we add as suffix and the string already contains $, we won't be able to get the right length info. 

    Add as prefix does not have this problem as the very first time we see a $, we know the length info is right prior to this $. 

 1 public class Solution {
 2     /**
 3      * @param strs a list of strings
 4      * @return encodes a list of strings to a single string.
 5      */
 6     public String encode(List<String> strs) {
 7         // Write your code here
 8         StringBuilder result = new StringBuilder();
 9         for(String str : strs){
10             result.append(String.valueOf(str.length()) + "$");
11             result.append(str);
12         }
13         return result.toString();
14     }
15 
16     /**
17      * @param str a string
18      * @return dcodes a single string to a list of strings
19      */
20     public List<String> decode(String str) {
21         // Write your code here
22         List<String> result = new LinkedList<String>();
23         int start = 0;
24         while(start < str.length()){
25             int idx = str.indexOf('$', start);
26             int size = Integer.parseInt(str.substring(start, idx));
27             result.add(str.substring(idx + 1, idx + size + 1));
28             start = idx + size + 1;
29         }
30         return result;
31     }
32 }

Runtime: Both solutions have a runtime of O(n * k), n is the number of strings, k is the average number of characters in each string.

Related Problems 

Binary Tree Serialization 

原文地址:https://www.cnblogs.com/lz87/p/7027290.html