算法-根據字符出現頻率排序

算法-根據字符出現頻率排序

1、根據字符出現頻率排序

451. 根據字符出現頻率排序

給定一個字符串,請將字符串裏的字符按照出現的頻率降序排列。

示例 1:

輸入:
"tree"

輸出:
"eert"

解釋:
'e'出現兩次,'r'和't'都只出現一次。
因此'e'必須出現在'r'和't'之前。此外,"eetr"也是一個有效的答案。
示例 2:

輸入:
"cccaaa"

輸出:
"cccaaa"

解釋:
'c'和'a'都出現三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正確的,因爲相同的字母必須放在一起。
示例 3:

輸入:
"Aabb"

輸出:
"bbAa"

解釋:
此外,"bbaA"也是一個有效的答案,但"Aabb"是不正確的。
注意'A'和'a'被認爲是兩種不同的字符。

本題是一個自hash的絕佳案例,完全可以利用Hash表的性質將時間複雜度優化爲O(N)
主要思想是建立一個counter數組,數組索引爲字符的ASCII碼值,數組內容爲字符出現的次數,然後我們每次都去搜索數組中最大的元素,搜索完成後將最大元素的出現次數置爲0(記憶化搜索),由於字符處於0-128之間,我們查找時間複雜度實際爲O(1).因此,總時間複雜度爲O(N)。

   public String frequencySort(String s) {
        if(s==null){
            return s;
        }
        int[] counter=new int[128];//自hash,統計字符出現次數
        char[] cs=s.toCharArray();
        for(char c:cs){
            counter[c]++;
        }

        int curr=0;
        while (curr<cs.length){
            int[] result=findMax(counter);//尋找出現次數最多的元素,返回元素和元素出現次數,時間複雜度O(128)也就是O(1)
            char c=(char) result[0];//找到的元素
            int count=result[1];//元素出現次數
            while (count-->0){
                cs[curr++]=c;//填充數據
            }
        }
        return new String(cs);

    }

    public int[] findMax(int[] counter){
        int count=0;
        int index=0;
        for(int i=0;i<='z';i++){
            if(counter[i]>count){
                count=counter[i];
                index=i;
            }
        }
        counter[index]=0;//使用完了,下次不再使用了
        return new int[]{index,count};
    }

執行的速度也是極快的,目前leetcode除我之外,最快速度是3ms,而我的算法達到了2ms

執行用時 :2 ms, 在所有 Java 提交中擊敗了100.00%的用戶
內存消耗 :40.3 MB, 在所有 Java 提交中擊敗了11.11%的用戶

其實本算法還有可以優化的地方,指出兩點:
1、函數調用有調用棧開銷,因此可以將每次尋找最大值的地方放到循環體裏面去,而不是使用一個子函數
2、本方法時間複雜度雖然爲O(N),但是其實還是可以改進的,我們只對出現過的字符進行判斷就好了。

針對第1點,可以做如下優化

    public String frequencySort(String s) {
        if(s==null){
            return s;
        }
        int[] counter=new int[128];//自hash,統計字符出現次數
        char[] cs=s.toCharArray();
        for(char c:cs){
            counter[c]++;
        }
        int curr=0;
        while (curr<cs.length){
            int count=0;
            char c=0;
            for(int i=0;i<='z';i++){
                if(counter[i]>count){
                    count=counter[i];
                    c=(char)i;
                }
            }
            counter[c]=0;//使用完了,下次不再使用了
            while (count-->0){
                cs[curr++]=c;//填充數據
            }
        }
        return new String(cs);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章