leetcode题解-451. 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.
有题目知,本题目的是按照字符串出现次数多少进行排序并返回新的数组。其中次数相同的字符次序不作要求,大小写算不同的字符处理。本题乍一看很简单,对字符串进行遍历计数似乎就解决了,但是仔细一想,字符和其出现次数的对应关系该用什么数据结构进行记录呢,特别是要对次数进行排序,排序之后二者关系又该如何对应。这都是我们要考虑的问题。
首先可能会想到使用map来保存字符和其出现次数的对应关系,然后再用一个数组(其索引是出现次数而值是相应的字符或者字符串(如果多个字符出现次数相同))来排序,在之后反向遍历该数组生成最终的字符串。代码入下,击败了33%的用户:

    public String frequencySort(String s) {
        if (s == null) {
            return null;
        }
        Map<Character, Integer> map = new HashMap();
        char[] charArray = s.toCharArray();
        int max = 0;
        for (Character c : charArray) {
            if (!map.containsKey(c)) {
                map.put(c, 0);
            }
            map.put(c, map.get(c) + 1);
            max = Math.max(max, map.get(c));
        }

        List<Character>[] array = buildArray(map, max);

        return buildString(array);
    }

    private List<Character>[] buildArray(Map<Character, Integer> map, int maxCount) {
        List<Character>[] array = new List[maxCount + 1];
        for (Character c : map.keySet()) {
            int count = map.get(c);
            if (array[count] == null) {
                array[count] = new ArrayList();
            }
            array[count].add(c);
        }
        return array;
    }

    private String buildString(List<Character>[] array) {
        StringBuilder sb = new StringBuilder();
        for (int i = array.length - 1; i > 0; i--) {
            List<Character> list = array[i];
            if (list != null) {
                for (Character c : list) {
                    for (int j = 0; j < i; j++) {
                        sb.append(c);
                    }
                }
            }
        }
        return sb.toString();
    }

想想该怎么改进呢,我们之前的题目中也经常使用数组(索引是次数、字符等信息)来代替map保存我们想要的信息,所以这里也可以使用这种方法进行改进,这种方法击败了93%的用户,代码入下。

    public String frequencySort1(String s){
        if(s.length()<3)
            return s;
        int [] map = new int [256];
        int max = 0;
        for(Character c:s.toCharArray()){
            map[c] ++;
            max = Math.max(max, map[c]);
        }
        String[] buckets = new String[max + 1];
        for(int i=0; i<256; i++){
            String str = buckets[map[i]];
            if(map[i] > 0)
                buckets[map[i]] = (str == null)? "" + (char)i : (str + (char)i);
        }
        StringBuilder strb = new StringBuilder();
        for(int i=max; i>=0; i--){
            if(buckets[i] != null)
                for(char c:buckets[i].toCharArray())
                    for(int j=0; j<i; j++)
                        strb.append(c);
        }
        return strb.toString();
    }

此外,我还看到一种使用map保存排序信息的方法,这种方法思想和上面两种方法是一样的,击败了78%的用户,代码入下:

public String frequencySort2(String s) {
        char[] arr = s.toCharArray();

        // bucket sort
        int[] count = new int[256];
        for(char c : arr) count[c]++;

        // count values and their corresponding letters
        Map<Integer, List<Character>> map = new HashMap<>();
        for(int i = 0; i < 256; i++){
            if(count[i] == 0) continue;
            int cnt = count[i];
            if(!map.containsKey(cnt)){
                map.put(cnt, new ArrayList<Character>());
            }
            map.get(cnt).add((char)i);
        }

        // loop throught possible count values
        StringBuilder sb = new StringBuilder();
        for(int cnt = arr.length; cnt > 0; cnt--){ 
            if(!map.containsKey(cnt)) continue;
            List<Character> list = map.get(cnt);
            for(Character c: list){
                for(int i = 0; i < cnt; i++){
                    sb.append(c);
                }
            }
        }
        return sb.toString();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值