347. 前 K 个高频元素-M
label : heap K、topK
给定一个非空的整数数组,返回其中出现频率前 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 是数组的大小。
分析:
求topK,一般用堆接可以解决了,因为堆的调整跟堆大小有关,所以我们可以将堆固定为k+1大小,调整小顶堆,然后pop最小的元素,这时为k大小的堆,这样扫描完所有数据,最后堆中就是剩下的topK,然后逆序输出就可以。时间复杂度nlogK。
技巧:关于引用类型和数值类型
如果引用对象(slice、map、channel)作为参数,修改数据很方便,因为data是再它们内部是指针引用的,所以我们修改的是间接数据;但是如果要修改这些引用对象的直接数据,就需要使用指针进行。
另外数组是数值类型,若要修改外部变量,请使用指针
package main
import "fmt"
func main() {
A := []int{1, 2, 3}
fmt.Println(A) //1 2 3
func(v []int) {
v[0] = 0
}(A)
fmt.Println(A) //0 2 3
func(v []int) {
v = v[:2]
}(A)
fmt.Println(A) //0 2 3
func(v *[]int) {
*v = (*v)[:2]
}(&A)
fmt.Println(A) //0 2
//--------- array is val object
B := [3]int{1, 2, 3}
fmt.Println(B) // 1 2 3
func(v [3]int) {
v[0] = 0
}(B)
fmt.Println(B) //1 2 3
func(v *[3]int) {
(*v)[0] = 0
}(&B)
fmt.Println(B) //0 2 3
}
nlogK算法,固定堆大小:
package main
import (
"container/heap"
"fmt"
)
type meta struct{
key,cnt int
}
type Heap []meta
func (hp Heap)Len()int{
return len(hp)
}
func (hp Heap)Swap(i,j int){
hp[i],hp[j]=hp[j],hp[i]
}
func (hp Heap)Less(i,j int)bool{
return hp[i].cnt<hp[j].cnt
}
func (hp* Heap)Push(v interface{}){
//要修改slice了,所以得用指针
*hp=append(*hp,v.(meta))
}
func (hp* Heap)Pop()interface{}{
x:=(*hp)[len(*hp)-1]
*hp=(*hp)[:len(*hp)-1]
return x
}
/*
执行用时 :20 ms, 在所有 Go 提交中击败了97.78%的用户
内存消耗 :6.3 MB, 在所有 Go 提交中击败了78.79%的用户
*/
func topKFrequent(nums []int, k int) []int {
mp:=make(map[int]int)
for i:=0;i<len(nums);i++{
mp[nums[i]]+=1
}
var hp Heap
for i,v:=range mp{
heap.Push(&hp,meta{i,v})
if hp.Len()>k{
heap.Pop(&hp)
}
}
if hp.Len()==0{
return []int{}
}
heap.Init(&hp)
ret:=make([]int,k)
for i:=k-1;i>=0;i--{
ret[i]=heap.Pop(&hp).(meta).key
}
return ret
}
func main() {
tables:=[][]int{
{1,1,1,2,2,2,2,3},{2},
{},{0},
{1,1,1,9,2,2,3},{2},
{1},{1},
{3,0,1,0},{1},
}
for i:=0;i<len(tables);i+=2{
fmt.Println(topKFrequent(tables[i],tables[i+1][0]))
}
}
同样,这也是用堆做的,但时间复杂度是nlog(n),因为这里没有固定对的大小,进当作对于golang heap的学习测试吧
package main
import (
"container/heap"
"fmt"
)
//仅战胜17.78%
type meta struct{
key,cnt int
}
type Heap []meta
func (hp Heap)Len()int{
return len(hp)
}
func (hp Heap)Swap(i,j int){
hp[i],hp[j]=hp[j],hp[i]
}
func (hp Heap)Less(i,j int)bool{
return hp[i].cnt>hp[j].cnt
}
func (hp* Heap)Push(v interface{}){
//要修改slice了,所以得用指针
*hp=append(*hp,v.(meta))
}
func (hp* Heap)Pop()interface{}{
x:=(*hp)[len(*hp)-1]
*hp=(*hp)[0:len(*hp)-1]
return x
}
func topKFrequent(nums []int, k int) []int {
fmt.Println(nums,k)
mp:=make(map[int]int)
for i:=0;i<len(nums);i++{
mp[nums[i]]+=1
}
var hp Heap
for i,v:=range mp{
fmt.Println(i,v)
hp.Push(meta{i,v})
}
heap.Init(&hp)
fmt.Println(hp)
ret:=make([]int,k)
for i:=0;i<k;i++{
ret[i]=heap.Pop(&hp).(meta).key
}
return ret
}
func main() {
tables:=[][]int{
{1,1,1,2,2,2,2,3},{2},
{},{0},
{1,1,1,9,2,2,3},{2},
{1},{1},
{3,0,1,0},{1},
}
for i:=0;i<len(tables);i+=2{
fmt.Println(topKFrequent(tables[i],tables[i+1][0]))
}
}