451. 根据字符出现频率排序
题目
给定一个字符串 s
,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。
返回 已排序的字符串 。如果有多个答案,返回其中任何一个。
提示:
1 <= s.length <= 5 * 105
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 - 利用 vector
自定义排序
- 使用无序map存储字符和出现次数映射关系
- 在vector中存储pair对,利用vector自定义排序
class Solution {
public:
string frequencySort(string s) {
unordered_map<int,int> hashmap;
for(char ch : s){
++hashmap[ch];
}
string result;
vector<pair<int,int>> vec;
for (const auto &m : hashmap) {
vec.push_back(m);
}
sort(vec.begin(),vec.end(),[] (const pair<int,int> &p1, const pair<int,int> &p2){
return p1.second > p2.second;
});
for(const auto & v : vec){
for(int i = 0;i < v.second;i++){
result += v.first;
}
}
return result;
}
};
题解2 - 利用优先队列
来自利用优先队列
当使用 pair<int, char>
作为 priority_queue
的元素类型时,C++ 会使用 std::less<pair<int, char>>
作为默认的比较函数。std::less<pair<int, char>>
的行为是首先比较 pair
的第一个元素(在这个例子中是 int
类型的频率)。如果第一个元素相等,它会继续比较第二个元素(在这个例子中是 char
类型的字符)。
class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> ump;
for (const auto &c : s) {
++ump[c];
}
priority_queue<pair<int, char>> pq;
for (const auto &m : ump) {
pq.push({m.second, m.first});
}
string ret;
while (!pq.empty()) {
auto t = pq.top();
pq.pop();
ret.append(t.first, t.second);
}
return ret;
}
};
C++相关语法: pair
模板类
在 C++ 标准库中,pair
是一个模板类,用于存储一对元素,这两个元素可以是不同的数据类型。pair
通常用于函数返回两个值的场景,或者在容器中存储两个相关联的数据项。
例如,如果你有一个 pair<int, int>
类型的对象,它可以存储两个 int
类型的值。pair
提供了两个公开的成员变量 first
和 second
,分别用于访问这对元素中的第一个和第二个值。
vector<pair<int,int>> vec;
这里定义了一个 vector
,它的元素类型是 pair<int, int>
。这意味着 vec
可以存储一系列整数对,每个整数对由两个 int
类型的值组成。你可以使用 vec.push_back(make_pair(a, b))
来添加新的整数对到这个向量中,其中 a
和 b
是你想要存储的两个整数。你也可以通过下标操作符 []
或者迭代器来访问和修改向量中的元素。
访问pair<int,int>
的元素使用first
和second
,注意不要括号!!!
for(const auto & v : vec){
for(int i = 0;i < v.second;i++){
result += v.first;
}
}
C++相关语法:利用 vector
自定义排序
sort(vec.begin(),vec.end(),[] (const pair<int,int> &p1, const pair<int,int> &p2){
return p1.second > p2.second;
});
这段代码是 C++ 中使用 std::sort
函数对 vector<pair<int, int>>
类型的容器 vec
进行排序的示例。std::sort
是 C++ 标准库中的一个非常强大的算法,它可以根据指定的比较函数对序列进行排序。
这里的 sort
函数调用包含三个部分:
-
vec.begin(), vec.end()
:这是要排序的范围,begin()
返回指向vec
第一个元素的迭代器,end()
返回指向vec
末尾(最后一个元素之后的位置)的迭代器。 -
一个 lambda 表达式作为比较函数:
[] (const pair<int,int> &p1, const pair<int,int> &p2) { return p1.second > p2.second; }
。这个 lambda 表达式接收两个pair<int, int>
类型的参数p1
和p2
,并返回一个布尔值。如果p1.second
大于p2.second
,则返回true
,表示p1
应该排在p2
后面;否则返回false
,表示p1
应该排在p2
前面。这里的比较是基于pair
的second
成员进行的。 -
排序的行为:由于 lambda 表达式中使用了
>
操作符,所以sort
函数会将vec
中的元素按照pair
的second
成员从大到小的顺序进行排序。
简而言之,这段代码的作用是将 vec
中的元素按照每个元素的 pair
的 second
成员值从大到小排序。如果 second
成员值相同,则 first
成员的值不会影响排序结果,因为 std::sort
只考虑提供的比较函数。
C++相关语法:头文件 <queue>
中的优先队列 priority_queue
在 C++ 中,优先队列是一种特殊的队列,它不遵循先进先出(FIFO)的原则,而是根据元素的优先级来出队。在 C++ 标准库中,优先队列是通过std::priority_queue
容器适配器实现的。std::priority_queue
默认是一个最大堆,即队首元素是最大的。如果你需要一个最小堆,可以通过传递一个自定义的比较函数来实现。
-
自动排序:优先队列在插入新元素时会自动根据元素的优先级进行排序。
-
只访问队首元素:你只能访问优先队列的队首元素,即优先级最高的元素。
-
不提供索引访问:与
std::vector
或std::list
不同,你不能通过索引直接访问优先队列中的元素。 -
构造:可以指定一个比较函数来定义优先级。
-
push
:向队列中添加元素。 -
pop
:移除队首元素。 -
top
:访问队首元素,但不移除它。 -
empty
:检查队列是否为空。 -
size
:返回队列中的元素数量。
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main() {
// 创建一个最小堆优先队列
priority_queue<int, vector<int>, greater<int>> minHeap;
priority_queue<int> maxHeap;
// 添加元素
minHeap.push(30);
minHeap.push(10);
minHeap.push(20);
// 打印队首元素
cout << "The smallest element is " << minHeap.top() << endl;
// 移除队首元素
minHeap.pop();
// 再次打印队首元素
cout << "The next smallest element is " << minHeap.top() << endl;
return 0;
}