今天是day10
题目一:滑动窗口最大值,要求从一个大小为k的滑动窗口从数组的最左端移动到数组的最右侧最终返回窗口中的最大值
from collections import deque
class MyQueue:
def __init__(self):
"双端队列"
self.queue = deque()
def pop(self,value):
"确保队列不为空且要弹出的值等于队列中的第一个值"
"因为队列是单调递减的,所以当队列的第一个值等于当前要弹出的值时,这个值应该是队列中最大的值。"
if self.queue and value == self.queue[0]:
self.queue.popleft()
def push(self,value):
"确保队列不为空且当前要添加的值大于队列中最后一个值"
"因为当前值大于队尾值,所以队尾值不可能成为滑动窗口中的最大值,需要被移除。"
while self.queue and value > self.queue[-1]:
self.queue.pop()
"将当前值添加到队列的右端,保持队列的单调递减性质"
self.queue.append(value)
def front(self):
return self.queue[0]
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
que = MyQueue()
result = []
"对于给定的滑动数组长度进行分割将值直接推入队列"
for i in range(k):
que.push(nums[i])
"此时确保了队列的值的单调,即第一个数值必定为最大值,故直接将其加入至result中"
result.append(que.front())
"如下几步实现了滑动"
for i in range(k,len(nums)):
que.pop(nums[i-k])
que.push(nums[i])
result.append(que.front())
return result
type MyQueue struct {
queue []int
}
//初始化声明一个数组
func NewMyQueue() *MyQueue{
return &MyQueue{
queue:make([]int,0),
}
}
//取数组的第一个元素
func (m *MyQueue) Front() int{
return m.queue[0]
}
//取数组的最后一个元素
func (m *MyQueue) Back() int{
return m.queue[len(m.queue)-1]
}
//判空
func (m *MyQueue) Empty() bool {
return len(m.queue) == 0
}
//确保队列不为空且当前要添加的值大于队列中最后一个值,因为当前值大于队尾值,所以队尾值不可能成为滑动窗口中的最大值,需要被移除
func (m *MyQueue) Push(val int) {
for !m.Empty()&& val > m.Back() {
m.queue = m.queue[:len(m.queue)-1]
}
m.queue = append(m.queue,val)
}
//因为队列是单调递减的,所以当队列的第一个值等于当前要弹出的值时,这个值应该是队列中最大的值
func (m *MyQueue) Pop(val int) {
if !m.Empty() && val == m.Front() {
m.queue = m.queue[1:]
}
}
func maxSlidingWindow(nums []int, k int) []int {
queue :=NewMyQueue()
length := len(nums)
res := make([]int,0)
for i:=0;i<k;i++{
queue.Push(nums[i])
}
res = append(res,queue.Front())
for i:=k;i<length;i++{
queue.Pop(nums[i-k])
queue.Push(nums[i])
res = append(res,queue.Front())
}
return res
}
题目二:
前k个高频元素,给定一个非空的整数数组,返回其中的出现频率前k个高的元素
"导入 Python 的 heapq 模块,该模块提供了堆(heap)相关的函数和类。"
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
map_ = {}
"统计数组中每个元素的出现频率,并将其存储在字典 map_ 中。如果字典中不存在该元素,则初始化其出现频率为 0,然后加 1。"
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i],0) + 1
"创建了一个空列表 pri_que,用于存储元素频率和元素值的元组,并将其作为堆(heap)使用。"
pri_que = []
"将元素的频率和值作为一个元组 (freq, key),压入堆 pri_que 中。由于 Python 的堆默认是最小堆(即根节点的值最小),所以这里存储的是 (频率, 元素值) 的元组。"
for key,freq in map_.items():
heapq.heappush(pri_que,(freq,key))
"如果堆的大小超过了 k,则执行下面的操作。这是为了保持堆中始终只有前 k 高的元素。"
if len(pri_que) > k:
heapq.heappop(pri_que)
result = [0] * k
"逆向遍历 result 列表,从后向前依次填充元素。"
for i in range(k-1,-1,-1):
"将堆 pri_que 中的元素依次弹出,并将其值(即元素值)赋给 result[i],这样 result 列表中存储的就是出现频率前 k 高的元素。"
result[i] = heapq.heappop(pri_que)[1]
return result
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
time_dict = defaultdict(int)
for num in nums:
"更新字典 time_dict 中元素 num 的出现频率,如果 num 不在字典中,则默认值为 0。"
time_dict[num] +=1
index_dict = defaultdict(list)
for key in time_dict:
"将元素 key 添加到字典 index_dict 中对应频率的列表中。"
index_dict[time_dict[key]].append(key)
"获取字典 index_dict 的所有键(即出现的频率),并转换为列表。"
key = list(index_dict.keys())
"频率小的元素会排在列表的前面。"
key.sort()
result = []
cnt = 0
"循环条件是频率列表不为空且已经添加到 result 中的元素个数不等于 k。"
while key and cnt != k:
"将频率列表中最大的频率对应的元素列表添加到 result 中。"
result += index_dict[key[-1]]
"更新已经添加到 result 中的元素个数。"
cnt += len(index_dict[key[-1]])
"弹出频率列表中最大的频率。"
key.pop()
"返回 result 列表中前 k 个元素,即出现频率前 k 高的元素。"
return result[0:k]
//这行定义了一个新的类型 IHeap,它是一个切片,每个元素是长度为 2 的整数数组
type IHeap [][2] int
//这段代码定义了类型 IHeap 的方法 Len(),返回切片的长度,它实现了 heap.Interface 接口的 Len() 方法
func (h IHeap) Len() int {
return len(h)
}
//这段代码定义了类型 IHeap 的方法 Less(),用于定义堆的排序规则。这里是根据切片中元素的第二个值进行比较,从小到大排序。它实现了 heap.Interface 接口的 Less() 方法。
func (h IHeap) Less(i,j int) bool {
return h[i][1] < h[j][1]
}
//这段代码定义了类型 IHeap 的方法 Swap(),用于交换切片中的两个元素。它实现了 heap.Interface 接口的 Swap() 方法。
func (h IHeap) Swap(i,j int) {
h[i],h[j] = h[j],h[i]
}
//这段代码定义了类型 IHeap 的方法 Push(),用于向堆中添加元素。它首先将接收到的元素类型转换为 [2]int,然后将其追加到切片中。
func (h *IHeap) Push(x interface{}) {
*h = append(*h,x.([2]int))
}
//这段代码定义了类型 IHeap 的方法 Pop(),用于从堆中弹出元素。它首先保存当前堆的副本,然后获取最后一个元素,并将切片的长度减少 1。最后,返回被弹出的元素。
func (h *IHeap) Pop() interface{} {
old:=*h
n:=len(old)
x:=old[n-1]
*h = old[0:n-1]
return x
}
//这段代码是解决「前 K 个高频元素」问题的主要函数。它首先创建了一个映射 map_num,用于存储每个元素的频率。然后创建了一个 IHeap 类型的指针 h,并通过 heap.Init() 方法将其初始化为空堆。
func topKFrequent(nums []int, k int) []int {
map_num := map[int]int{}
for _,item := range nums{
map_num[item] ++
}
h:=&IHeap{}
heap.Init(h)
//这是一个循环,遍历了 map_num 中的键值对,即元素及其频率。
for key,value := range map_num{
//将元素及其频率作为一个长度为 2 的数组 [2]int 添加到堆 h 中。
heap.Push(h,[2]int{key,value})
//如果堆的长度超过了 k,则执行以下操作:heap.Pop(h):从堆中弹出一个元素,因为我们只需要前 k 个高频元素。
if h.Len()>k{
heap.Pop(h)
}
}
//创建一个长度为 k 的整数切片 res,用于存储前 k 个高频元素。遍历 res 中的每个位置。从堆中弹出元素 [2]int,并将其中的第一个值(元素本身)存储到 res 中。这里之所以使用 k-i-1 是因为堆是按照从小到大排序的,而我们需要的是前 k 个高频元素,所以要从 res 的末尾开始存储。
res:=make([]int,k)
for i:=0;i<k;i++{
res[k-i-1] = heap.Pop(h).([2]int)[0]
}
return res
}
func topKFrequent(nums []int, k int) []int {
ans:=[]int{}
//初始化一个映射 map_num,用于统计每个数字在切片 nums 中出现的次数。
map_num:=map[int]int{}
//遍历切片 nums 中的每个元素 item,并将元素作为键存储在 map_num 中,值为该元素出现的次数。这样,map_num 就记录了 nums 中每个元素的频率。
for _,item:=range nums {
map_num[item]++
}
//遍历 map_num 中的键(即切片 nums 中的元素),并将键添加到结果切片 ans 中。这样,ans 中存储的是 nums 中出现过的不重复的元素。
for key,_ := range map_num{
ans = append(ans,key)
}
//使用 sort.Slice 函数对切片 ans 进行排序。排序的方式是根据每个元素在 map_num 中对应的值(即元素在 nums 中出现的频率)进行降序排序。
sort.Slice(ans,func (a,b int) bool {
return map_num[ans[a]] > map_num[ans[b]]
})
//返回排序后的结果切片 ans 的前 k 个元素,即出现频率最高的前 k 个元素。
return ans[:k]
}