# 【基础篇 - Day 20】 2020-11-19 - 347. 前 K 个高频元素
# 题目描述
# 入选理由
- 哈希表用于频次计算
# 题目描述
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2: 输入: nums = [1], k = 1 输出: [1]
提示:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。 你可以按任意顺序返回答案。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/top-k-frequent-elements 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
# 加餐
# 我的回答
https://github.com/leetcode-pp/91alg-2/issues/46#issuecomment-730288843
# 解法一
# 时空复杂度
n 是数字的种数
时间复杂度:O(nlogn) 排序的复杂度
空间复杂度: O(n)
明天再看看传说中的顶堆
var topKFrequent = function (nums, k) {
let map = {}
for (let i = 0; i < nums.length; i++) {
map[nums[i]] = map[nums[i]] ? map[nums[i]] + 1 : 1
}
return Object.keys(map).sort((a, b) => map[b] - map[a]).slice(0, k)
};
# 解法二
主要是堆的实现,厚颜无耻的抄过来就没什么难度了
# 时间复杂度
堆化:heapify(): 时间复杂度 O(logn)
建堆:init() :时间复杂度 O(n)
排序:sort():时间复杂度 O(nlogn)
class Heap {
constructor(list = [], comparator) {
this.list = list;
if (typeof comparator != 'function') {
this.comparator = function comparator (target, compared) {
return target < compared;
};
} else {
this.comparator = comparator;
}
this.init();
}
init () {
const size = this.size();
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
this.heapify(this.list, size, i);
}
}
insert (n) {
this.list.push(n);
this.init()
}
peek () {
return this.list[0];
}
pop () {
const last = this.list.pop();
if (this.size() === 0) return last;
const returnItem = this.list[0];
this.list[0] = last;
this.heapify(this.list, this.size(), 0);
return returnItem;
}
replace (n) {
this.list[0] = n
this.init()
}
sort () {
let k = this.size() - 1;
let sortArr = [...this.list]
while (k > 1) {
[sortArr[0], sortArr[k]] = [sortArr[k], sortArr[0]]
--k;
this.heapify(sortArr, k, 0);
}
return sortArr
}
size () {
return this.list.length;
}
heapify (arr, size, i) {
let largest = i;
const left = i * 2 + 1;
const right = i * 2 + 2;
if (left < size && this.comparator(arr[largest], arr[left]))
largest = left;
if (right < size && this.comparator(arr[largest], arr[right]))
largest = right;
if (largest !== i) {
[arr[largest], arr[i]] = [arr[i], arr[largest]];
this.heapify(arr, size, largest);
}
}
}
class MaxHeap extends Heap {
constructor(list, comparator) {
super(list, comparator);
}
}
class MinHeap extends Heap {
constructor(list, comparator) {
if (typeof comparator != 'function') {
comparator = function comparator (inserted, compared) {
return inserted > compared;
};
}
super(list, comparator);
}
}
# 大顶堆
时间复杂度:O(klogn) K 堆大小
空间复杂度: O(n)
var topKFrequent = function (nums, k) {
let map = {}
for (let i = 0; i < nums.length; i++) {
map[nums[i]] = map[nums[i]] ? map[nums[i]] + 1 : 1
}
const mapArr = Object.entries(map)
const res = []
// 大顶堆
const maxFunc = (target, compared) => target[1] < compared[1]
let topK = new MaxHeap(mapArr, maxFunc);
while (k--) {
res.push(topK.pop()[0])
}
return res
};
# 小顶堆
时间复杂度:O(nlogk) K 是堆大小
空间复杂度: O(n)
= =为什么两个顶堆都没昨天的 sort 排序块 不讲道理
var topKFrequent = function (nums, k) {
let map = {}
for (let i = 0; i < nums.length; i++) {
map[nums[i]] = map[nums[i]] ? map[nums[i]] + 1 : 1
}
const mapArr = Object.entries(map)
const heap = []
const res = []
// 小顶堆
const minFunc = (target, compared) => target[1] > compared[1]
let topK
for (let i = 0; i < mapArr.length; i++) {
const node = mapArr[i]
if (i < k) {
heap.push(node)
if (i == k - 1) topK = new MinHeap(heap, minFunc);
} else if (node[1] > topK.list[0][1]) {
topK.replace(node)
}
}
return topK.list.map(v => v[0])
};
# 解法三
时间复杂度:O(n) N 是数字种类
空间复杂度: O(n) Map 的空间
快速选择
const swap = (arr, l, r) => ([arr[l], arr[r]] = [arr[r], arr[l]])
function quickSelect(nums, left, right, k) {
const random = Math.floor(Math.random() * (right - left + 1)) + left
swap(nums, right, random)
// 将i作为挡板
let i = left
let j = left
while (j < right) {
if (nums[j][1] < nums[right][1]) swap(nums, i++, j)
j++
}
swap(nums, i, j)
// 交换完毕,num[i]就是 第i小的数
// 即 第i大的数 就是 right - i +1
if (k == right - i + 1) return nums.slice(i)
// top K 在左边
if (k < right - i + 1) return quickSelect(nums, i + 1, right, k)
// top K 在右边
return quickSelect(nums, left, i - 1, k - (right - i + 1))
}
var topKFrequent = function (nums, k) {
let map = {}
for (let i = 0; i < nums.length; i++) {
map[nums[i]] = map[nums[i]] ? map[nums[i]] + 1 : 1
}
let arr = Object.entries(map)
return quickSelect(arr, 0, arr.length - 1, k).map(v => v[0])
};