271. Encode and Decode Strings


July-15-2019
这个题蛮有意思的,有2种做法。
第一种是encode的时候escape character。
比如用#来区分不同String,遇到String里有#怎么办,加个别的符号%在前面。
String里有%怎么办,再加个%%在前面。
最后的结果就是,#单独出现的话,说明是新的String;遇到%的话可能是%%或者%#代表确实是String的字符。

public class Codec {

    // Encodes a list of strings to a single string.
    public String encode(List<String> strs) {
        StringBuilder sb = new StringBuilder();
        strs.stream().forEach(str -> {
            for (char c : str.toCharArray()) {
                if (c == '#') {
                    sb.append("%#");
                } else if (c == '%') {
                    sb.append("%%");
                } else {
                    sb.append(c);
                }
            }
            sb.append('#');
        });
        
        return sb.toString();
    }

    // Decodes a single string to a list of strings.
    public List<String> decode(String s) {
        List<String> res = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i ++) {
            char c = s.charAt(i);
            if (c == '%') {
                sb.append(s.charAt(++ i));
            } else if (c == '#') {
                res.add(sb.toString());
                sb = new StringBuilder();
            } else {
                sb.append(c);
            }
        }
        return res;
    }
}

另一种做法是加个header作为metadata。length_1#str_1length2#str_2
[“abc”, “ab”] => “3#abc2#ab”

**string.indexOf("#", index) -> 从i开始第一个出现"#"的位置。手动操作I也行= =

public class Codec {

    // Encodes a list of strings to a single string.
    public String encode(List<String> strs) {
        StringBuilder sb = new StringBuilder();
        for (String s : strs) {
            sb.append(s.length() + "#" + s);
        }
        return sb.toString();
    }

    // Decodes a single string to a list of strings.
    public List<String> decode(String s) {
        List<String> res = new ArrayList<>();
        int lenStart = 0;
        while (lenStart < s.length()) {
            int lenEnd = s.indexOf("#", lenStart);
            int tempStrLen = Integer.valueOf(s.substring(lenStart, lenEnd));
            res.add(s.substring(lenEnd + 1, lenEnd + 1 + tempStrLen));
            lenStart = lenEnd + 1 + tempStrLen;
        }
        return res;
    }
}

二刷。
15-Nov-2016

这个题挺有意思的,感觉工作中很容易遇到这种情况,不过我没找到工作,次奥。。

一刷用的方法是记录每个string的长度,做一个类似于bitmap的东西。最后encoded string还要记录MAP的每个字符串长度的整数的长度。。大概是这样的
MAP1#长度1#长度2#长度3#长都4#Str1Str2Str3
|map1|----------------MAP---------------|-----字符串-----|

实际上不用这么麻烦。。。。。

思路还是一样的,要记录每个字符串的长度,还自己选个分隔符。
encode的时候按顺序就行了。
{"ab", "b", "abc"} =》
"2#ab 1#b 3#abc" 实际中间是没有空格的,有空格看着清楚些。

这样最后decode的时候从左边开始,找分隔符,找到之后passed substring就标记长度的整数,记录下俩,然后按整数在分隔符的基础上读取相应的位,再找下一个分隔符。

Time: O(k)
k = num of Strings
Space: O(n + k)

public class Codec {

    // Encodes a list of strings to a single string.
    public String encode(List<String> strs) {
        StringBuilder sb = new StringBuilder();
        for (String s: strs) {
            sb.append(s.length()).append("#").append(s);
        }
        return sb.toString();
    }

    // Decodes a single string to a list of strings.
    public List<String> decode(String s) {
        List<String> res = new ArrayList<>();
        int i = 0;
        while (i < s.length()) {
            int next = s.indexOf('#', i);
            int length = Integer.valueOf(s.substring(i, next));
            res.add(s.substring(next + 1, next + 1 + length));
            i = next + length + 1;
        }
        
        return res;
    }
}

string1.indexOf(char1, index);记得用。。从index开始第一个出现的char1,或者-1.

这是一个通用的办法。
“长度+分隔符+字符串”

另一个办法是escaping..

选一个分隔符,比如#,再选一个escaping character,比如/。

我们在原来数组里的#前面加个escaping character,那原来数组里的#就变成了/#。

我们在原来数组里的/前面加个escaping character,那原来数组里的/就变成了//。

有人要问了:如果原来的数组里有//#怎么办?
我们在原来数组里的/前面加个escaping character,,那原来数组里的//#就变成了////#。

有人要问了:如果原来的数组里有////#怎么办?
我们在原来数组里的/前面加个escaping character,,那原来数组里的////#就变成了////////#。

有人要问了:如果原来的数组里有////////#怎么办?
我们在原来数组里的/前面加个escaping character,,那原来数组里的////////#就变成了////////////////#。
有人要问了:如果我变成回忆,最怕我太不争气,顽固地赖在空气霸占你心里,每一寸缝隙

主要想说的是,decode的时候,遇到/我们直接跳过当前,添加他后面的char,/#的#会被直接写入,而不是当做分隔符。
原来的/#经过encode变成///#,decode的时候第一个/被跳过,直接添加第二个/,然后又遇到一个/,再跳过,直接添加#.

Time: O(n)
Space: O(n)

2个方法是时间和空间的取舍,第一个快,按字符串添加,但是需要额外空间记录长度;第二个慢,按字符一个一个添加,但是不用记录字符串长度了,额外空间少。

public class Codec {

    // Encodes a list of strings to a single string.
    public String encode(List<String> strs) {
        StringBuilder sb = new StringBuilder();
        
        for (String s: strs) {
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (c == '#') sb.append("/#");
                else if (c == '/') sb.append("//");
                else sb.append(c);
            }
            sb.append('#');
        }
        return sb.toString();
    }

    // Decodes a single string to a list of strings.
    public List<String> decode(String s) {
        List<String> res = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '/') {
                sb.append(s.charAt(++i));
            } else if (c == '#') {
                res.add(sb.toString());
                sb = new StringBuilder();
            } else {
                sb.append(c);
            }
        }
        
        return res;
    }
}
posted @ 2017-01-14 04:45  哇呀呀..生气啦~  阅读(235)  评论(0编辑  收藏  举报