347. 前 K 个高频元素-M

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]))
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值