[leetcode] Sort Characters By Frequency

Given a string, sort it in decreasing order based on the frequency of characters.

Example 1:

Input:
"tree"

Output:
"eert"

Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.

Example 2:

Input:
"cccaaa"

Output:
"cccaaa"

Explanation:
Both 'c' and 'a' appear three times, so "aaaccc" is also a valid answer.
Note that "cacaca" is incorrect, as the same characters must be together.

Example 3:

Input:
"Aabb"

Output:
"bbAa"

Explanation:
"bbaA" is also a valid answer, but "Aabb" is incorrect.
Note that 'A' and 'a' are treated as two different characters.

 分析:这个题目还是蛮有意思的,题目表述的也非常简洁,就是按照字符串中字符出现频率由高到低输出一个新的字符串。思路还是比较清晰的,用一个Hashmap存一下每个字符出现的次数,key就是出现的字符,value就是次数。关键就是怎么对values从大到小并且还要取出key。这里我的思路是把values放到一个数组里,然后用Arrays.sort方法直接排序,就得到了从大到小的value。然后对每个value,再去遍历map.get(key)。代码如下:
 1 class Solution {
 2     public String frequencySort(String s) {
 3         Map<Character,Integer> map = new HashMap<>();
 4         List<Character> list = new ArrayList<>();
 5         for ( char c : s.toCharArray() )
 6             map.put(c,map.getOrDefault(c,0)+1);
 7         int[] frequency = new int[map.values().size()];
 8         int cur = 0;
 9         for ( int t : map.values() )
10             frequency[cur++] = t;
11         Arrays.sort(frequency);
12         StringBuilder res = new StringBuilder("");
13         for ( int i = frequency.length - 1 ; i >= 0 ; i -- ){
14             for ( char key : map.keySet() ){
15                 if ( map.get(key) == frequency[i] && !list.contains(key)) {
16                     for ( int z = 0 ; z < frequency[i] ; z++ ) res.append(key);
17                     list.add(key);
18                 }
19             }
20         }
21         return res.toString();
22     }
23 }

      时间复杂度介于O(n^2)到O(n^3)之间,运行时间为19ms,击败了89.43%的人。


      因为代码时间复杂度比较高,还有很多可以优化的空间。首先map可以用一个int[128]数组替换,这个前面已经说到过了;然后过程还可以再优化一下。代码如下:

 1 class Solution {
 2    public String frequencySort(String s) {
 3         int[] map = new int[128];    //map数组下标与出现次数对应
 4         int[] counter = new int[128]; //counter数组用来排序用的。不对应
 5         for ( char c : s.toCharArray() ) {
 6             map[c]+=1;
 7             counter[c]+=1;
 8         }
 9         Arrays.sort(counter);    //对counter数组排序
10         StringBuilder sb = new StringBuilder();
11         for ( int i = counter.length - 1 ; i >= 0 ; i -- ){  //对字符出现次数从大到小遍历
12             if ( counter[i] != 0 ){
13                 int count = counter[i];
14                 for ( int j = 0 ; j < map.length ; j ++ ){
15                     if ( map[j] == count ){
16                         for ( int k = 0 ; k < count ; k ++ ) sb.append((char) j);
17                         map[j] = 0;        //如果找到一个字符,就将它出现的次数置为0。
18                     }
19                 }
20             }
21         }
22         return sb.toString();
23     }
24 }

      上面代码的关键就是生成两个数组map和counter。两者都保存着字符出现的次数,不同的是map下标和出现次数是对应的,而counter只是为了从大到小遍历出现的次数。其他的过程与上面一种方法思路类似。

      运行时间6ms,击败了99.95%。表明map还是比较浪费时间的,以后遇到以char做key的map,都尽量使用int[128]数组来代替map,效率很高。

 

猜你喜欢

转载自www.cnblogs.com/boris1221/p/9290557.html