5
5
6
6
## 题目大意
7
7
8
- 给定一个字符串 ` s ` 。
8
+ ** 描述 ** : 给定一个字符串 ` s ` 。
9
9
10
- 要求 :将字符串 ` s ` 里的字符按照出现的频率降序排列。
10
+ ** 要求 ** :将字符串 ` s ` 里的字符按照出现的频率降序排列。如果有多个答案,返回其中任何一个 。
11
11
12
- ## 解题思路
12
+ ** 说明** :
13
+
14
+ - $1 \le s.length \le 5 * 10^5$。
15
+ - ` s ` 由大小写英文字母和数字组成。
16
+
17
+ ** 示例** :
18
+
19
+ ``` Python
20
+ 输入: s = " tree"
21
+ 输出: " eert"
22
+ 解释: ' e' 出现两次,' r' 和' t' 都只出现一次。
23
+ 因此' e' 必须出现在' r' 和' t' 之前。此外," eetr" 也是一个有效的答案。
24
+
25
+
26
+ 输入: s = " cccaaa"
27
+ 输出: " cccaaa"
28
+ 解释: ' c' 和' a' 都出现三次。此外," aaaccc" 也是有效的答案。
29
+ 注意" cacaca" 是不正确的,因为相同的字母必须放在一起。
30
+ ```
13
31
14
- 使用哈希表统计字符频率。然后使用 ` set ` 集合对字符串去重并转换为 ` list ` 数组。
32
+ ## 解题思路
15
33
16
- 然后按照字符频数对新的字符串数组进行排序。将堆中频数最高的元素依次加入答案数组中,并不断调整剩余元素构成的大顶堆。
34
+ ### 思路 1:优先队列
17
35
18
- 最后输出答案数组。
36
+ 1 . 使用哈希表 ` s_dict ` 统计字符频率。
37
+ 2 . 然后遍历哈希表 ` s_dict ` ,将字符以及字符频数存入优先队列中。
38
+ 3 . 将优先队列中频数最高的元素依次加入答案数组中。
39
+ 4 . 最后拼接答案数组为字符串,将其返回。
19
40
20
- ## 代码
41
+ ### 思路 1: 代码
21
42
22
43
``` Python
23
- class Solution :
24
- # 调整为大顶堆
25
- def heapify (self , nums , nums_dict , index , end ):
26
- left = index * 2 + 1
27
- right = left + 1
28
- while left <= end:
29
- # 当前节点为非叶子节点
30
- max_index = index
31
- if nums_dict[nums[left]] > nums_dict[nums[max_index]]:
32
- max_index = left
33
- if nums_dict[nums[left]] == nums_dict[nums[max_index]]:
34
- if nums[left] > nums[max_index]:
35
- max_index = left
36
- if right <= end and nums_dict[nums[right]] > nums_dict[nums[max_index]]:
37
- max_index = right
38
- if right <= end and nums_dict[nums[right]] == nums_dict[nums[max_index]]:
39
- if nums[right] > nums[max_index]:
40
- max_index = right
41
- if index == max_index:
42
- # 如果不用交换,则说明已经交换结束
43
- break
44
- nums[index], nums[max_index] = nums[max_index], nums[index]
45
- # 继续调整子树
46
- index = max_index
47
- left = index * 2 + 1
48
- right = left + 1
49
-
50
- # 初始化大顶堆
51
- def buildMaxHeap (self , nums , nums_dict ):
52
- size = len (nums)
53
- # (size-2) // 2 是最后一个非叶节点,叶节点不用调整
54
- for i in range ((size - 2 ) // 2 , - 1 , - 1 ):
55
- self .heapify(nums, nums_dict, i, size - 1 )
56
- return nums
57
-
58
- # 堆排序方法(本题未用到)
59
- def maxHeapSort (self , nums , nums_dict ):
60
- self .buildMaxHeap(nums)
61
- size = len (nums)
62
- for i in range (size):
63
- nums[0 ], nums[size - i - 1 ] = nums[size - i - 1 ], nums[0 ]
64
- self .heapify(nums, nums_dict, 0 , size - i - 2 )
65
- return nums
44
+ import heapq
66
45
46
+ class Solution :
67
47
def frequencySort (self , s : str ) -> str :
68
48
# 统计元素频数
69
49
s_dict = dict ()
@@ -72,19 +52,23 @@ class Solution:
72
52
s_dict[ch] += 1
73
53
else :
74
54
s_dict[ch] = 1
75
-
76
- # 使用 set 方法去重,得到新数组
77
- new_s = list (s)
78
- size = len (new_s)
79
- # 初始化大顶堆
80
- self .buildMaxHeap(new_s, s_dict)
81
- res = list ()
82
- for i in range (size):
83
- # 堆顶元素为当前堆中频数最高的元素,将其加入答案中
84
- res.append(new_s[0 ])
85
- # 交换堆顶和末尾元素,继续调整大顶堆
86
- new_s[0 ], new_s[size - i - 1 ] = new_s[size - i - 1 ], new_s[0 ]
87
- self .heapify(new_s, s_dict, 0 , size - i - 2 )
55
+
56
+ priority_queue = []
57
+ for ch in s_dict:
58
+ heapq.heappush(priority_queue, (- s_dict[ch], ch))
59
+
60
+ res = []
61
+ while priority_queue:
62
+ ch = heapq.heappop(priority_queue)[- 1 ]
63
+ times = s_dict[ch]
64
+ while times:
65
+ res.append(ch)
66
+ times -= 1
88
67
return ' ' .join(res)
89
68
```
90
69
70
+ ### 思路 1:复杂度分析
71
+
72
+ - ** 时间复杂度** :$O(n + k \times log_2k)$。其中 $n$ 为字符串 $s$ 的长度,$k$ 是字符串中不同字符的个数。
73
+ - ** 空间复杂度** :$O(n + k)$。
74
+
0 commit comments