前K个高频元素
- https://leetcode.cn/problems/top-k-frequent-elements/
描述
- 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2
输入: nums = [1], k = 1
输出: [1]
提示
- 1 <= nums.length <= 10510^5105
- k 的取值范围是 [1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
进阶
- 你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。
Typescript 版算法实现
1 )使用堆排序
class MinHeap {
heap: Record<string, any>[] = [];
// 交换节点位置
swap(i, j) {
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
}
// 获得父节点
getParentIndex(i) {
return (i - 1) >> 1;
}
// 获取左子节点
getLeftIndex(i) {
return (i << 1) + 1; // 极客写法
}
// 获取右子节点
getRightIndex(i) {
return (i << 1) + 2;
}
// 向上移动
shiftUp(index) {
// 如果到了堆顶元素,index是0,则不要再上移了
if(!index) return;
const parentIndex = this.getParentIndex(index)
if(this.heap[parentIndex]?.value > this.heap[index].value) {
this.swap(parentIndex, index)
this.shiftUp(parentIndex)
}
}
// 下移
shiftDown(index) {
// 边界1:如果到了堆尾元素,则不要再下移了
if(index >= this.heap.length - 1) return;
const size = this.size();
const leftIndex = this.getLeftIndex(index);
const rightIndex = this.getRightIndex(index);
if (leftIndex < size && this.heap[leftIndex]?.value < this.heap[index].value) {
this.swap(leftIndex, index);
this.shiftDown(leftIndex);
}
// 注意,这里的 this.heap[index].value 和上面重复,不能使用变量,因为上个if中存在 swap 和 shiftDown, 使用变量有可能出问题
if (rightIndex < size && this.heap[rightIndex]?.value < this.heap[index].value) {
this.swap(rightIndex, index);
this.shiftDown(rightIndex);
}
}
// 插入
insert(value) {
this.heap.push(value);
this.shiftUp(this.heap.length - 1);
}
// 删除堆顶
pop() {
// pop()方法删除数组最后一个元素并返回,赋值给堆顶
this.heap[0] = this.heap.pop();
// 对堆顶重新排序
this.shiftDown(0);
}
// 获取堆顶
peak() {
return this.heap[0];
}
// 获取堆的大小
size() {
return this.heap.length;
}
}
function topKFrequent(nums: number[], k: number): number[] {
const map = new Map();
nums.forEach(n => {
map.set(n, map.has(n)? map.get(n) + 1 : 1);
})
const h = new MinHeap();
map.forEach((value, key) => {
h.insert({value, key});
// 保证堆的尺寸是k
(h.size() > k) && h.pop();
})
return h.heap.map(a => a.key);
}
- 这里改造了之前的 MinHeap 最小堆类
- 原来是值比较,现在是对象的比较
2 )使用字典
function topKFrequent(nums: number[], k: number): number[] {
const map = new Map();
nums.forEach(n => {
map.set(n, map.has(n)? map.get(n) + 1 : 1);
})
// console.log(map); // 这是一个map结构
// console.log(Array.from(map)); // 将map转换为二维数组,[[值, 频率], [值, 频率]] 这是无序的
// 对Array.from(map)产生的二维矩阵进行频率的排序
const list = Array.from(map).sort((a,b) => b[1] - a[1])
return list.slice(0, k).map(i => i[0]); // 返回按频率排序的前K个元素值
}
- 统计每个元素出现的次数(频率)
- 通过Map结构来处理
- 分析时间复杂度:O(nlogn)
- 一个forEach循环O(n)
- 原生sort排序,O(nlogn)
- 总体来说O(nlogn)
- 如果题目要求,返回的前K个高频元素不考虑顺序,我们一下就要想到用堆排序
Python3 版算法实现
1 ) 方案1
class MinHeap:
def __init__(self):
self.heap = []
def swap(self, i, j):
self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
def get_parent_index(self, i):
return (i - 1) // 2
def get_left_index(self, i):
return (i << 1) + 1
def get_right_index(self, i):
return (i << 1) + 2
def shift_up(self, index):
if index == 0:
return
parent_index = self.get_parent_index(index)
if self.heap[parent_index]['value'] > self.heap[index]['value']:
self.swap(parent_index, index)
self.shift_up(parent_index)
def shift_down(self, index):
if index >= len(self.heap) - 1:
return
size = len(self.heap)
left_index = self.get_left_index(index)
right_index = self.get_right_index(index)
if left_index < size and self.heap[left_index]['value'] < self.heap[index]['value']:
self.swap(left_index, index)
self.shift_down(left_index)
if right_index < size and self.heap[right_index]['value'] < self.heap[index]['value']:
self.swap(right_index, index)
self.shift_down(right_index)
def insert(self, value):
self.heap.append(value)
self.shift_up(len(self.heap) - 1)
def pop(self):
if len(self.heap) <= 1:
return
self.heap[0] = self.heap.pop()
self.shift_down(0)
def peak(self):
return self.heap[0]
def size(self):
return len(self.heap)
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
from collections import Counter
freq_map = Counter(nums)
h = MinHeap()
for key, value in freq_map.items():
h.insert({'key': key, 'value': value})
if h.size() > k:
h.pop()
return [item['key'] for item in h.heap]
2 )方案2
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
from collections import Counter
freq_map = Counter(nums)
sorted_items = sorted(freq_map.items(), key=lambda x: x[1], reverse=True)
return [item[0] for item in sorted_items[:k]]
Golang 版算法实现
1 ) 方案1
type MinHeap struct {
heap []map[string]int
}
// 交换节点位置
func (h *MinHeap) swap(i, j int) {
h.heap[i], h.heap[j] = h.heap[j], h.heap[i]
}
// 获得父节点
func (h *MinHeap) getParentIndex(i int) int {
return (i - 1) >> 1
}
// 获取左子节点
func (h *MinHeap) getLeftIndex(i int) int {
return (i << 1) + 1
}
// 获取右子节点
func (h *MinHeap) getRightIndex(i int) int {
return (i << 1) + 2
}
// 向上移动
func (h *MinHeap) shiftUp(index int) {
if index == 0 {
return
}
parentIndex := h.getParentIndex(index)
if h.heap[parentIndex]["value"] > h.heap[index]["value"] {
h.swap(parentIndex, index)
h.shiftUp(parentIndex)
}
}
// 下移
func (h *MinHeap) shiftDown(index int) {
if index >= len(h.heap)-1 {
return
}
size := h.size()
leftIndex := h.getLeftIndex(index)
rightIndex := h.getRightIndex(index)
if leftIndex < size && h.heap[leftIndex]["value"] < h.heap[index]["value"] {
h.swap(leftIndex, index)
h.shiftDown(leftIndex)
}
if rightIndex < size && h.heap[rightIndex]["value"] < h.heap[index]["value"] {
h.swap(rightIndex, index)
h.shiftDown(rightIndex)
}
}
// 插入
func (h *MinHeap) insert(value map[string]int) {
h.heap = append(h.heap, value)
h.shiftUp(len(h.heap) - 1)
}
// 删除堆顶
func (h *MinHeap) pop() {
if len(h.heap) <= 1 {
return
}
h.heap[0] = h.heap[len(h.heap)-1]
h.heap = h.heap[:len(h.heap)-1]
h.shiftDown(0)
}
// 获取堆顶
func (h *MinHeap) peak() map[string]int {
return h.heap[0]
}
// 获取堆的大小
func (h *MinHeap) size() int {
return len(h.heap)
}
func topKFrequent(nums []int, k int) []int {
freqMap := make(map[int]int)
for _, n := range nums {
freqMap[n]++
}
h := &MinHeap{}
for key, value := range freqMap {
h.insert(map[string]int{"key": key, "value": value})
if h.size() > k {
h.pop()
}
}
result := make([]int, k)
for i, item := range h.heap {
result[i] = item["key"]
}
return result
}
2 )方案2
func topKFrequent(nums []int, k int) []int {
freqMap := make(map[int]int)
for _, n := range nums {
freqMap[n]++
}
type kv struct {
Key int
Value int
}
var list []kv
for k, v := range freqMap {
list = append(list, kv{k, v})
}
sort.Slice(list, func(i, j int) bool {
return list[i].Value > list[j].Value
})
result := make([]int, k)
for i := 0; i < k; i++ {
result[i] = list[i].Key
}
return result
}
462



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



