zoukankan      html  css  js  c++  java
  • [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,效率很高。

     
  • 相关阅读:
    你爱的不爱你,转身是幸福
    按字节长度截取字符串(支持截取带HTML代码样式的字符串)
    存储过程操作类
    C# 拖动控件
    文件同步类
    c# 动态改变控件大小的方法
    虚拟世界改变现实 盛大兴建永恒之塔
    c#百钱买百鸡
    序列化类
    DLL专题之MFC规则库和扩展库
  • 原文地址:https://www.cnblogs.com/boris1221/p/9290557.html
Copyright © 2011-2022 走看看