困难题:查找热点数据问题 | 豆包MarsCode AI刷题

77 阅读4分钟

1、问题

1.1 问题描述

给你一个整数数组 nums 和一个整数 k,请你用一个字符串返回其中出现频率前 k 高的元素。请按升序排列。

你所设计算法的时间复杂度必须优于 O(n log n),其中 n 是数组大小。

1.2 输入

  • nums: 一个正整数数组
  • k: 一个整数

1.3 返回

返回一个包含 k 个元素的字符串,数字元素之间用逗号分隔。数字元素按升序排列,表示出现频率最高的 k 个元素。

1.4 参数限制

  • 1 <= nums[i] <= 10^4
  • 1 <= nums.length <= 10^5
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

1.5 测试样例

样例1:

输入:nums = [1, 1, 1, 2, 2, 3], k = 2
输出:"1,2"
解释:元素 1 出现了 3 次,元素 2 出现了 2 次,元素 3 出现了 1 次。因此前两个高频元素是 1 和 2。

样例2:

输入:nums = [1], k = 1
输出:"1"

样例3:

输入:nums = [4, 4, 4, 2, 2, 2, 3, 3, 1], k = 2
输出:"2,4"

2、思路

为了满足时间复杂度的要求,我们的大体思路可以分为以下几个步骤:

  • 统计频率:遍历数组 nums,统计每个数字的出现频率。
  • 排序频率:将统计到的频率按降序排序。
  • 选择前 k 个元素:从排序后的频率中选择前 k 个元素。
  • 升序排序:对这 k 个元素按升序排序。
  • 转换为字符串:将结果转换为字符串格式,并用逗号分隔。

明确了整体思路之后,就开始对每个步骤进行实现,具体如下:

2.1 统计频率

我们使用一个字典 freq_dict 来存储每个数字的频率。遍历数组 nums,对于每个数字,如果它不在字典中,则将其添加到字典中并设置频率为 1;如果已经在字典中,则将其频率加 1。

# 用于存储每个数字的频率
freq_dict = {} 
# 统计每个数字的频率
for num in nums:
    if num not in freq_dict:
        freq_dict[num] = 1
    else:
        freq_dict[num] += 1

2.2 排序频率

将字典 freq_dict 按频率降序排序。这里使用 sorted 函数,并指定频率值,reverse=True 表示降序排序。

 # 按频率降序排序字典项
 freq_dict = sorted(freq_dict.items(), key=lambda d: d[1], reverse=True)

2.3 选择前 k 个元素

从排序后的列表中选择前 k 个元素。这里我们只关心元素的值,因此使用列表推导式提取前 k 个元素的值。

# 取前 k 个频率最高的元素
result = [item[0] for item in freq_dict[:k]]

2.4 升序排序

对这 k 个元素按升序排序。这里再次使用 sorted 函数,并指定 reverse=False 表示升序排序。

# 对结果按升序排序
result = sorted(result, reverse=False)

2.5 转换为字符串

将结果列表中的每个元素转换为字符串,并用逗号连接成一个字符串。

# 将结果转换为字符串
result = [str(item) for item in result]
return ','.join(result)

3、代码

整体代码如下:

def solution(nums, k):
    result = []
    freq_dict = {}  # 用于存储每个数字的频率
    # 统计每个数字的频率
    for num in nums:
        if num not in freq_dict:
            freq_dict[num] = 1
        else:
            freq_dict[num] += 1

    # 按频率降序排序字典项
    freq_dict = sorted(freq_dict.items(), key=lambda d: d[1], reverse=True)
    # 取前 k 个频率最高的元素
    result = [item[0] for item in freq_dict[:k]]
    # 对结果按升序排序
    result = sorted(result, reverse=False)
    # 将结果转换为字符串
    result = [str(item) for item in result]
    return ','.join(result)

4、运行结果

可以看到提交通过,说明我们的方法和代码都没有问题。 屏幕截图 2024-11-09 161723.png

5、总结分析

这5个步骤的时间复杂度分析如下:

  • 统计频率:遍历数组 nums,时间复杂度为 O(n)
  • 排序频率:排序字典项的时间复杂度为 O(n log n)
  • 选择前 k 个元素:时间复杂度为 O(k)
  • 升序排序:对 k 个元素排序的时间复杂度为 O(k log k)
  • 转换为字符串:时间复杂度为 O(k)

总体时间复杂度为 O(n + n log n + k log k),由于 k 通常远小于 n,因此可以近似为 O(n log n)。虽然这个时间复杂度不严格优于 O(n log n),但在实际应用中,k 通常较小,因此这个算法在大多数情况下还是比较高效的。

最后,也是希望同学们可以多多刷题,提升自己的思维能力和编码水平。