• 算法
    • 1.用数组当作简易哈希表,同时又能保证按照key有序遍历该哈希表
    • 2.首先统计字符串中字符个数
    • 3.然后每次都 “先从头到尾后从尾到头” 操作数组中非0的字符添加到结果字符串中
public String sortString(String s) {
    int n = s.length();
    int[] dict = new int[26];
    for (char c : s.toCharArray()) {
        dict[c-'a']++;
    }

    StringBuilder sb = new StringBuilder();
    while (sb.length() < n) {
        pick(dict, sb, true);
        pick(dict, sb, false);
    }
    return sb.toString();
}

private void pick(int[] dict, StringBuilder sb, boolean ascend) {
    for (int i = 0; i < 26; i++) {
        int j = ascend ? i : 25 - i;
        if (dict[j]-- > 0) {
            sb.append((char)(j+'a'));
        }
    }
}
func sortString(s string) string {
    count := make([]int, 26)
    for _, c := range s {
        count[c-'a']++
    }

    var result string
    for len(result) < len(s) {
        result = pick(count, result, true)
        result = pick(count, result, false)
    }
    return result
}

func pick(count []int, result string, ascend bool) string {
    for i := 0; i < 26; i++ {
        var j int
        if ascend {
            j = i
        } else {
            j = 25 - i
        }
        if count[j] > 0 {
            result += string(rune(j + 'a'))
            count[j]--
        }
    }
    return result
}
  • 算法
    • 1.使用TreeMap达到同样的效果
    • 2.注意细节
      • 2.1 需要使用TreeMap获得的keySet去初始化一个TreeSet,做深拷贝;而不是直接赋值给一个TreeSet/NavigableSet,做浅拷贝,这样在遍历的时候删除其中的key回出现并发修改错误
      • 2.2 注意以下两种初始化TreeSet的区别
        • new TreeSet<>(treeMap.keySet()):返回的TreeSet一定是按照key升序的
        • new TreeSet(treeMap.keySet()):返回的TreeSet的key顺序依赖于里面的treeMap的key顺序,里面是key升序他就是key升序,里面是key降序他就是key降序
public String sortString(String s) {
    int n = s.length();
    TreeMap<Character, Integer> treeMap = new TreeMap<>();
    for (char c : s.toCharArray()) {
        treeMap.put(c, treeMap.getOrDefault(c, 0) + 1);
    }

    boolean ascend = true;
    StringBuilder sb = new StringBuilder();
    while (sb.length() < n) {
        TreeSet<Character> characters = ascend ? new TreeSet<>(treeMap.keySet()) : new TreeSet(treeMap.descendingKeySet());
        for (char c : characters) {
            sb.append(c);
            treeMap.put(c, treeMap.get(c) - 1);
            treeMap.remove(c, 0);
        }
        ascend = !ascend; // ascend ^= ascend;
    }
    return sb.toString();
}