Description
給定一個字串
s,若沒有兩個不同字元的出現頻率相同,則稱為「好字串」。回傳使s變成好字串所需的最少刪除次數。
Example:
Input: s = “aaabbbcc” Output: 2 (刪除兩個 ‘b’ 或兩個 ‘c’)
Intuition#
統計頻率後,從高到低貪心地將重複頻率往下降。
- 統計每個字元的出現次數
- 對頻率排序(從大到小)
- 若當前頻率已被使用,就一直減少直到找到未使用的頻率或變成 0
Approaches#
1: HashSet 檢查#
- 概念: 用 HashSet 記錄已使用的頻率,有衝突就不斷減一。
- 時間複雜度:
O(n + k^2),k 為不同字元數(最多 26) - 空間複雜度:
O(k)
class Solution {
fun minDeletions(s: String): Int {
val freq = IntArray(26)
for (c in s) freq[c - 'a']++
val used = HashSet<Int>()
var deletions = 0
for (f in freq) {
var cur = f
while (cur > 0 && cur in used) {
cur--
deletions++
}
if (cur > 0) used.add(cur)
}
return deletions
}
}⭐2: 排序 + 貪心#
- 概念: 將頻率由大到小排序,確保每個頻率嚴格小於前一個(不超過前一個 - 1 且不低於 0)。
- 時間複雜度:
O(n + k log k) - 空間複雜度:
O(k)
class Solution {
fun minDeletions(s: String): Int {
val freq = IntArray(26)
for (c in s) freq[c - 'a']++
freq.sortDescending()
var deletions = 0
for (i in 1 until 26) {
if (freq[i] == 0) break
if (freq[i] >= freq[i - 1]) {
val target = maxOf(0, freq[i - 1] - 1)
deletions += freq[i] - target
freq[i] = target
}
}
return deletions
}
}🔑 Takeaways#
- Pattern: 頻率去重 — 統計頻率後貪心調整
- 關鍵技巧: 排序後從高到低處理,每個頻率不超過前一個減一;HashSet 方式更直觀但邏輯相同