這題從題意上面就可以得知它是希望你算出頻率,基本上這也是很標準 Heap 的題型。
先來看一下這個問題原文長怎樣?
Given a string s
, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string.
Return the sorted string. If there are multiple answers, return any of them.
Example 1:
Input: s = “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: s = “cccaaa”
Output: “aaaccc”
Explanation: Both ‘c’ and ‘a’ appear three times, so both “cccaaa” and “aaaccc” are valid answers.
Note that “cacaca” is incorrect, as the same characters must be together.
Example 3:
Input: s = “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.
Constraints:
s
consists of uppercase and lowercase English letters and digits.
給定你一個字串,需要你回傳一個字串,依照出現的頻率來排列,也就是說當你字元的頻率出現的越高,則位置越前面,舉個例子來說,假設 "abca"
則會輸出 "aabc"
,此時你會好奇,那 'b'
跟 'c'
頻率一樣,誰先誰後,照題目來看,其實他不在意,因此,任何一種順序都是合法的。
這邊要算次數,我們很直覺的就會想到使用 Map 來裝,所以在這樣的情況下,就會宣告一個 HashMap 來處理,首先我們將 Key 設定為字串內的字元, Value 則是裝字元出現的次數
,所以我們可以這樣來進行宣告表示。
val hashMap = HashMap<Char, Int>()
for(i in s.indices){
hashMap[s[i]] = hashMap.getOrDefault(s[i], 0)+1
}
接著我們可以宣告一個 MaxHeap 來幫我們排序已經儲存的好的 Map 元素,之前我們都只是使用內建的變數型態來當作 Heap 的多型處理,現在如果要裝入 Map 的 Key 與 Value 型態,那應該怎麼處理呢?很簡單,其實你可以透過 Map.Entry
物件或者 Pair
物件來進行存取,
val maxHeap = PriorityQueue<Map.Entry<Char,Int>>(){ e1, e2->
e2.value - e1.value
}
//或者
val maxHeap = PriorityQueue<Pair<Char,Int>>(){ p1, p2->
p2.second - e1.second
}
其中要注意的是,如果你使用 Pair
物件型態,則 Pair.first
代表 Key,而 Pair.second
代表的是 Value,還有另外一種表示方式就是自己宣告一個 class 裡面裝著 Key 與 Value 的物件也是可以的哦。
如果你是直接使用 Map.Entry 的方式處理,則裝進 Map 可以直接透過 Map.addAll()
的方式直接把 Map 倒入到 Heap 內。
maxHeap.addAll(hashMap.entries)
接著因為我們需要把結果 String 產出,所以我們透過了 StringBuilder 來協助我們裝結果字串。
val result = StringBuilder(s.length)
接著我們需要把 Heap 內部的物件全部吐出來,由於吐出來是我們的 Map.Entry 物件,因此,抓到 Key 之後,還要根據 Value 來決定產出幾次的字元。
while(maxHeap.isNotEmpty()){
val entry = maxHeap.poll()
for(i in 0..entry.value-1){
result.append(entry.key)
}
}
如此一來就可以把最終結果輸出了。
return result.toString()
以下就是完整程式碼。
class Solution {
fun frequencySort(s: String): String {
val hashMap = HashMap<Char, Int>()
val size = s.length - 1
for(i in 0..size){
hashMap[s[i]] = hashMap.getOrDefault(s[i], 0)+1
}
val maxHeap = PriorityQueue<Map.Entry<Char,Int>>(){e1,e2->
e2.value - e1.value
}
maxHeap.addAll(hashMap.entries)
val sortString = StringBuilder(s.length)
while(maxHeap.isNotEmpty()){
val entry = maxHeap.poll()
for(i in 0..entry.value-1){
sortString.append(entry.key)
}
}
return sortString.toString()
}
}
這邊可以看出我們的複雜度,首先把字串裝進 Map 就是 O(N),接著再把 Map 的值丟進 Heap,每次進去都會進行排序,所以整體就會是 O(NLogN),但是這邊注意到我們根據題目限制只會存在26個字母(大小寫)以及數字,所以充其量就只是 62 次,因此這邊的複雜度就會是 O(1),所以我們可以知道下方的迴圈都其實最多 62 次,都可以視為 O(1),因此,整體複雜度就會是一開始的計算次數 O(N)
。