根据字符出现频率排序
- https://leetcode.cn/problems/sort-characters-by-frequency/
描述
- 给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。
- 返回 已排序的字符串 。如果有多个答案,返回其中任何一个。
示例 1
输入: s = "tree"
输出: "eert"
解释: 'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。
示例 2
输入: s = "cccaaa"
输出: "cccaaa"
解释: 'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正确的,因为相同的字母必须放在一起。
示例 3
输入: s = "Aabb"
输出: "bbAa"
解释: 此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意'A'和'a'被认为是两种不同的字符。
提示
- 1 <= s.length <= 5 * 10510^5105
- s 由大小写英文字母和数字组成
Typescript 版算法实现
1 )方案1:普通方法实现, 基于原生sort和Map结构
function frequencySort(s: string): string {
// 1. 构建map字典,例如: Map{a: 2, b: 3}
const map = new Map();
s.split('').forEach(item => {
map.set(item, map.has(item) ? map.get(item) + 1 : 1);
});
// 2. 将map转成二维数组进行排序
const arr = Array.from(map);
arr.sort((a, b) => b[1] - a[1]);
// 3. 基于排好序的数组(降序)组装成最终结果
let result = '';
arr.forEach((item) => {
result += item[0].repeat(item[1]);
})
return result;
};
- 这里使用平时最简单的原生排序法,结合Map数据结构的特性,和ES6中字符串的特性完成
- 原生排序,性能不错 O(nlogn),推荐
2 )使用堆排序
class MaxHeap {
map: Map<string, number> = new Map()
heap: number[] = []
init(str:string) {
// 构建map字典
const { map } = this;
str.split('').forEach(item => {
map.set(item, map.has(item) ? map.get(item) + 1 : 1);
});
this.heap = Array.from(map.values());
}
sort () {
const iArr = this.heap;
const n = iArr.length;
if (n <= 1) return iArr;
for (let i = Math.floor(n / 2); i >= 0; i--) {
MaxHeap.maxHeapify(iArr, i, n);
}
for (let j = 0; j < n; j++) {
MaxHeap.swap(iArr, 0, n - 1 - j);
MaxHeap.maxHeapify(iArr, 0, n - 1 - j - 1);
}
return iArr;
}
// 排序并转成字符串
sortToString () {
const arr = this.sort(); // 这里对值进行排序
const str = [];
while (arr.length) {
const top = arr.pop();
for (const [k, v] of this.map) {
// 值和值匹配
if (v === top) {
str.push(k.repeat(v));
this.map.delete(k); // 使用过的key防止重复匹配 这里记得删除
break
}
}
}
return str.join('');
}
// 交换两个元素
static swap (arr, i, j) {
if (i === j) return;
[arr[i], arr[j]] = [arr[j], arr[i]];
}
// 构建最大堆的过程
static maxHeapify (Arr, i, size) {
// 左节点(索引)
const l = (i << 1) + 1;
// 右节点
const r = (i << 1) + 2;
let largest = i;
// 父节点i和左节点l做比较取最大
if (l <= size && Arr[l] > Arr[largest]) largest = l;
// 右节点和最大值比较
if (r <= size && Arr[r] > Arr[largest]) largest = r;
if (largest !== i) {
MaxHeap.swap(Arr, i, largest);
MaxHeap.maxHeapify(Arr, largest, size);
}
}
}
function frequencySort(s: string): string {
const mh = new MaxHeap();
mh.init(s);
return mh.sortToString();
}
- 如果这个堆之前构建好,只需要少许修改,即可投入使用
- 理解了最大堆的构建过程,这个还是比较推荐使用的
- 需要注意的是在while和for的嵌套循环中的时间复杂度的考量
- while是每次pop从n直到为0,因此是 n
- for不会每次都执行n次,匹配到时会被break掉,因此是 logn
- 所以整体时间复杂度为 O(nlogn)
Python3 版算法实现
1 )方案1:常规字典做法
class Solution:
def frequencySort(self, s: str) -> str:
# 1. 构建字典,例如: {'a': 2, 'b': 3}
char_count = {}
for char in s:
if char in char_count:
char_count[char] += 1
else:
char_count[char] = 1
# 2. 将字典转成列表进行排序
sorted_items = sorted(char_count.items(), key=lambda x: x[1], reverse=True)
# 3. 基于排好序的列表(降序)组装成最终结果
result = ''.join(char * count for char, count in sorted_items)
return result
2 ) 方案2:堆排序
class MaxHeap:
def __init__(self):
self.map = {}
self.heap = []
def init(self, s: str):
# 构建map字典
for char in s:
self.map[char] = self.map.get(char, 0) + 1
self.heap = list(self.map.values())
def sort(self):
i_arr = self.heap
n = len(i_arr)
if n <= 1:
return i_arr
for i in range(n // 2, -1, -1):
self.max_heapify(i_arr, i, n - 1)
for j in range(n):
self.swap(i_arr, 0, n - 1 - j)
self.max_heapify(i_arr, 0, n - 1 - j - 1)
return i_arr
def sort_to_string(self):
arr = self.sort() # 这里对值进行排序
result = []
while arr:
top = arr.pop()
for k, v in self.map.items():
if v == top:
result.append(k * v)
del self.map[k] # 使用过的key防止重复匹配 这里记得删除
break
return ''.join(result)
@staticmethod
def swap(arr, i, j):
if i == j:
return
arr[i], arr[j] = arr[j], arr[i]
@staticmethod
def max_heapify(arr, i, size):
l = (i << 1) + 1
r = (i << 1) + 2
largest = i
if l <= size and arr[l] > arr[largest]:
largest = l
if r <= size and arr[r] > arr[largest]:
largest = r
if largest != i:
MaxHeap.swap(arr, i, largest)
MaxHeap.max_heapify(arr, largest, size)
class Solution:
def frequencySort(self, s: str) -> str:
mh = MaxHeap()
mh.init(s)
return mh.sort_to_string()
Golang 版算法实现
1 )方案1:map常规做法
func frequencySort(s string) string {
// 1. 构建map字典,例如: map[a]int{a: 2, b: 3}
charCount := make(map[rune]int)
for _, char := range s {
charCount[char]++
}
// 2. 将map转成切片进行排序
type kv struct {
Key rune
Value int
}
var arr []kv
for k, v := range charCount {
arr = append(arr, kv{k, v})
}
sort.Slice(arr, func(i, j int) bool {
return arr[i].Value > arr[j].Value
})
// 3. 基于排好序的切片(降序)组装成最终结果
var result strings.Builder
for _, item := range arr {
result.WriteString(strings.Repeat(string(item.Key), item.Value))
}
return result.String()
}
2 ) 方案2:堆
type MaxHeap struct {
mapCount map[rune]int
heap []int
}
func NewMaxHeap() *MaxHeap {
return &MaxHeap{
mapCount: make(map[rune]int),
heap: []int{},
}
}
func (mh *MaxHeap) Init(s string) {
for _, char := range s {
mh.mapCount[char]++
}
mh.heap = make([]int, len(mh.mapCount))
i := 0
for _, count := range mh.mapCount {
mh.heap[i] = count
i++
}
}
func (mh *MaxHeap) Sort() {
heap := mh.heap
n := len(heap)
if n <= 1 {
return
}
for i := n / 2; i >= 0; i-- {
mh.maxHeapify(heap, i, n-1)
}
for j := 0; j < n; j++ {
mh.swap(heap, 0, n-1-j)
mh.maxHeapify(heap, 0, n-1-j-1)
}
}
func (mh *MaxHeap) SortToString() string {
mh.Sort()
var result strings.Builder
for len(mh.heap) > 0 {
top := mh.heap[len(mh.heap)-1]
mh.heap = mh.heap[:len(mh.heap)-1]
for k, v := range mh.mapCount {
if v == top {
result.WriteString(strings.Repeat(string(k), v))
delete(mh.mapCount, k)
break
}
}
}
return result.String()
}
func (mh *MaxHeap) swap(arr []int, i, j int) {
if i == j {
return
}
arr[i], arr[j] = arr[j], arr[i]
}
func (mh *MaxHeap) maxHeapify(arr []int, i, size int) {
l := (i << 1) + 1
r := (i << 1) + 2
largest := i
if l <= size && arr[l] > arr[largest] {
largest = l
}
if r <= size && arr[r] > arr[largest] {
largest = r
}
if largest != i {
mh.swap(arr, i, largest)
mh.maxHeapify(arr, largest, size)
}
}
func frequencySort(s string) string {
mh := NewMaxHeap()
mh.Init(s)
return mh.SortToString()
}
1398



被折叠的 条评论
为什么被折叠?



