题目内容与要求
问题描述
给定一个整数数组 nums
和一个整数 k
,请用一个字符串返回其中出现频率前 k
高的元素。请按升序排列。
输入
nums
: 一个正整数数组k
: 一个整数
返回
返回一个包含 k
个元素的字符串,数字元素之间用逗号分隔。数字元素按升序排列,表示出现频率最高的 k
个元素。
思路解析
为了高效地解决这个问题,我们需要以下几个步骤:
- 统计频率:使用哈希表(
unordered_map
)来统计每个元素的出现频率。 - 构建频率对:将频率信息转换为一个包含频率对的向量(
vector<pair<int, int>>
),其中每个元素是一个对,包含元素值和对应的频率。 - 排序:按频率降序排序这些频率对。
- 提取前
k
个元素:从排序后的频率对中提取前k
个元素的值。 - 排序并转换为字符串:对提取出的元素进行排序,并将它们转换为字符串形式,元素之间用逗号分隔。
代码解释
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
#include <set>
using namespace std;
string solution(vector<int> nums, int k) {
// 使用unordered_map统计每个元素的出现次数
unordered_map<int, int> frequency;
for (int num : nums) {
++frequency[num];
}
// 将频率信息转换为pair容器
vector<pair<int, int>> freqs(frequency.begin(), frequency.end());
// 按频率降序排序
sort(freqs.begin(), freqs.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
return a.second > b.second;
});
// 提取前k个不同元素
vector<int> topK;
for (int i = 0; i < min(k, static_cast<int>(freqs.size())); ++i) {
topK.push_back(freqs[i].first);
}
// 对topK进行排序
sort(topK.begin(), topK.end());
// 转换成字符串形式
string result;
for (size_t i = 0; i < topK.size(); ++i) {
if (i != 0) result += ",";
result += to_string(topK[i]);
}
return result;
}
时间复杂度分析
-
统计频率:
- 使用
unordered_map
统计每个元素的出现次数,时间复杂度为 O(n),其中 n 是数组的大小。
- 使用
-
构建频率对:
- 将
unordered_map
中的数据复制到vector<pair<int, int>>
中,时间复杂度为 O(n)。
- 将
-
排序:
- 使用
std::sort
对频率对进行排序,时间复杂度为 O(n log n)。
- 使用
-
提取前
k
个元素:- 遍历排序后的频率对,提取前
k
个元素,时间复杂度为 O(k)。
- 遍历排序后的频率对,提取前
-
对结果进行排序:
- 对提取出的前
k
个元素进行排序,时间复杂度为 O(k log k)。
- 对提取出的前
-
构建结果字符串:
- 构建结果字符串,时间复杂度为 O(k)。
综合以上步骤,优化后的整体时间复杂度主要由统计频率和排序决定,因此总的时间复杂度为 O(n + n log n) = O(n log n)。
核心知识
- 哈希表(
unordered_map
):用于高效地统计元素的出现频率。 - 排序算法(
std::sort
):用于对频率对进行排序。 - 容器(
vector
和pair
):用于存储和处理数据。 - 字符串处理:用于将结果转换为字符串形式。
总结
通过使用 unordered_map
统计频率、vector<pair<int, int>>
存储频率对以及 std::sort
进行排序,我们能够高效地找出出现频率最高的前 k
个元素,并按升序排列。这种方法的时间复杂度为 O(n log n),优于原始的 O(n^2) 方法,特别是在处理大规模数据时,性能提升显著。通过这种方式,代码不仅更加简洁易读,而且执行效率也得到了显著提升。