英文:
Remove element from the Priority queue
问题
// 这个示例演示了使用堆接口构建的优先队列。
package main
import (
"container/heap"
"fmt"
)
// Item 是我们在优先队列中管理的东西。
type Item struct {
value int // 项目的值;任意值。
priority int // 项目在队列中的优先级。
// 索引由 update 方法所需,并由 heap.Interface 方法维护。
index int // 项目在堆中的索引。
}
// PriorityQueue 实现了 heap.Interface 并保存 Item。
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
// 我们希望 Pop 给我们最高的优先级,所以这里使用大于号。
return pq[i].value > pq[j].value
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = j
pq[j].index = i
}
func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
item.index = -1 // 为了安全起见
*pq = old[0 : n-1]
return item
}
// update 修改队列中项目的优先级和值。
func (pq *PriorityQueue) update(item *Item, value int, priority int) {
item.value = value
item.priority = priority
heap.Fix(pq, item.index)
}
func main() {
nums := []int{1, 3, 2, -3, 5, 3, 6, 7, 8, 9}
k := 3
result := maxSlidingWindow(nums, k)
fmt.Println("result", result)
}
func maxSlidingWindow(nums []int, k int) {
pq := make(PriorityQueue, len(nums))
res := []int{}
for i := 0; i < k; i++ {
pq[i] = &Item{
value: nums[i],
priority: nums[i],
index: i,
}
res = append(res, nums[i])
}
heap.Init(&pq)
peek := pq[0]
fmt.Println(peek.value) // 这是一个最大堆,给出最大的元素
temp := heap.Pop(&pq).(*Item)
fmt.Println("temp:", temp)
remove := heap.Remove(&pq, 0).(*Item)
// pq = slices.Delete(pq, 5)
fmt.Println("remove:", remove)
for i := 0; i < len(nums); i++ {
// 从优先队列中删除所需的元素
// 将下一个元素插入优先队列
// 查看最高值
}
}
英文:
// This example demonstrates a priority queue built using the heap interface.
package main
import (
"container/heap"
"fmt"
)
// An Item is something we manage in a priority queue.
type Item struct {
value int // The value of the item; arbitrary.
priority int // The priority of the item in the queue.
// The index is needed by update and is maintained by the heap.Interface methods.
index int // The index of the item in the heap.
}
// A PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
// We want Pop to give us the highest, not lowest, priority so we use greater than here.
return pq[i].value > pq[j].value
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = j
pq[j].index = i
}
func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
item.index = -1 // for safety
*pq = old[0 : n-1]
return item
}
// update modifies the priority and value of an Item in the queue.
func (pq *PriorityQueue) update(item *Item, value int, priority int) {
item.value = value
item.priority = priority
heap.Fix(pq, item.index)
}
func main() {
nums := []int{1, 3, 2, -3, 5, 3, 6, 7, 8, 9}
k := 3
result := maxSlidingWindow(nums, k)
fmt.Println("result", result)
}
func maxSlidingWindow(nums []int, k int) {
pq := make(PriorityQueue, len(nums))
res := []int{}
for i := 0; i < k; i++ {
pq[i] = &Item{
value: nums[i],
priority: nums[i],
index: i,
}
res = append(res, nums[i])
}
heap.Init(&pq)
peek := pq[0]
fmt.Println(peek.value) // its a maxheap and gives the largest element
temp := heap.Pop(&pq).(*Item)
fmt.Println("temp:", temp)
remove := heap.Remove(&pq, 0).(*Item)
// pq = slices.Delete(pq, 5)
fmt.Println("remove:", remove)
for i:=0;i<len(nums);i++{
//remove the desired element from the priority Queue
// insert the next element in the Priority queue
// peek the highest value
}
}
I am trying to print the maximum value in a sliding window. Putting the elements of window size, here k = 3 into the priority queue(Maxheap) and then peek the value.
"heap.Init(&pq)" will assign the index in pq based on the priority. Look for maxSlidingWindow function, the last for loop prints the max element for each window of size k. If you compare the indices in the pq and the nums array the indices will be different. And hence deleting the desired element from the priority queue seems almost impossible.
答案1
得分: 1
你的问题不够清楚。我假设你希望你的maxSlidingWindow
函数的行为如下:
maxSlidingWindow([]int{1, 3, 2,-3, 5, 3, 6, 7, 8, 9}, 3)
返回 --> []int{3, 3, 5, 5, 6, 7, 8, 9}
为了实现这个功能,可以按照以下步骤进行操作:
-
从
nums
中取出前k
个值,填充优先队列(priority queue)。你的代码将
nums
中的所有值都放入了队列,这似乎不像是一个滑动窗口的方法。我对你的问题是否理解正确有所怀疑。 -
从队列中取出最大值,将其添加到
result
中。 -
对于
k
到len(Data) - 1
的i
:-
从优先队列中删除
nums[i-k]
元素,并将nums[i]
推入队列。你应该使用
heap.Remove
来删除一个元素。Go的heap.Fix
提供了一种将删除和推入步骤结合起来的方法。 -
取修改后的优先队列的最大值,将其添加到
result
中。
-
此外,你的队列实现有一个错误:
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = j // 应该是:pq[i].index = i
pq[j].index = i // 应该是:pq[j].index = j
}
从优先队列中删除元素
根据问题的标题,似乎你无法让这部分工作起来:
从优先队列中删除
nums[i-k]
元素,并将nums[i]
推入队列
使用Go的heap
,要修改一个元素(使用heap.Fix
)或删除一个元素(使用heap.Remove
),需要知道该元素的索引。为了获得相应的索引,至少有两种方法。
请注意,我们需要区分nums
中元素的索引和队列中元素的索引。我将在以下代码中将前者称为i
,后者称为j
。我们知道要删除的元素的i
,但由于heap
会改变队列,我们需要找到j
。
遍历队列并找到元素
这种方法很简单。这种情况下,你可以简化PriorityQueue
类型:
type PriorityQueue []int
// 我将跳过heap.Interface部分
func maxSlidingWindow(nums []int, k int) []int {
pq := make(PriorityQueue, k)
result := make([]int, 0, len(nums)-k+1)
for i := 0; i < k; i++ { // 1.
pq[i] = nums[i]
}
heap.Init(&pq)
result = append(result, pq[0]) // 2.
for i := k; i < len(nums); i++ {
for j, value := range pq { // 3.1.
if value == nums[i-k] {
pq[j] = nums[i] // 不是删除再推入
heap.Fix(&pq, j) // 使用heap.Fix修改内容
break
}
}
result = append(result, pq[0]) // 3.2.
}
return result
}
它可以正确处理重复值。
保持外部的i -> j
映射
以下只是一种可能的方法,可能不太优雅。我使用CircularArray
来保持我们的映射:
type CircularArray []int
func (a CircularArray) wrapped(index int) int {
return index % len(a)
}
func (a CircularArray) Get(index int) int {
return a[a.wrapped(index)]
}
func (a CircularArray) Set(index int, value int) {
a[a.wrapped(index)] = value
}
func (a CircularArray) Swap(i, j int) {
ii, jj := a.wrapped(i), a.wrapped(j)
a[ii], a[jj] = a[jj], a[ii]
}
type PriorityQueue struct {
Window []int // 队列
IndicesOfIndices CircularArray // `i -> j`映射
}
// func (pq *PriorityQueue) Len() ...
func (pq *PriorityQueue) Push(x interface{}) {} // 不使用
func (pq *PriorityQueue) Pop() interface{} { return nil } // 不使用
func (pq *PriorityQueue) Less(a, b int) bool {
return pq.Window[a] > pq.Window[b]
}
func (pq *PriorityQueue) Swap(a, b int) {
pq.Window[a], pq.Window[b] = pq.Window[b], pq.Window[a]
pq.IndicesOfIndices.Swap(a, b)
}
func maxSlidingWindow(nums []int, k int) []int {
pq := PriorityQueue{
Window: make([]int, 0, k),
IndicesOfIndices: make(CircularArray, k),
}
result := make([]int, 1, len(nums)-k+1)
for i := 0; i < k; i++ {
pq.PushWithIndex(nums[i], i) // 1.
}
heap.Init(&pq)
result[0] = pq.Window[0] // 2.
for i := k; i < len(nums); i++ {
result = append(result, pq.NextWithIndex(nums[i], i)) // 3.
}
return result
}
// 推入队列并设置`i -> j`映射
func (pq *PriorityQueue) PushWithIndex(value int, i int) {
pq.IndicesOfIndices.Set(i, len(pq.Window))
pq.Window = append(pq.Window, value)
}
// 更新队列并返回最大元素
func (pq *PriorityQueue) NextWithIndex(pushed int, i int) int {
j := pq.IndicesOfIndices.Get(i) // 3.1.
pq.Window[j] = pushed
heap.Fix(pq, j)
return pq.Window[0] // 3.2.
}
英文:
Your question is not clear enough. I assume that you want your maxSlidingWindow
to behave like this:
maxSlidingWindow([]int{1, 3, 2,-3, 5, 3, 6, 7, 8, 9}, 3)
returns --> []int{3, 3, 5, 5, 6, 7, 8, 9}
To achieve this, one might do the following:
-
Fill a priority queue with the first
k
values fromnums
.Your code is putting all values from
nums
into the queue, which does not seem like a moving window approach. And I do doubt if I misunderstand your question. -
Take the max value from the queue, append it to the
result
. -
For i from
k
tolen(Data) - 1
:-
Discard the
nums[i-k]
element from the priority queue, and push into the queuenums[i]
.You should use use
heap.Remove
to remove an element. Go'sheap.Fix
provides a way to combine the removing and pushing steps. -
Take the max value of the modified priority queue, append it to the
result
.
-
Also, your implementation of the queue has a bug:
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = j // should be: pq[i].index = i
pq[j].index = i // should be: pq[j].index = j
}
Removing elements from priority queues
According to the title of the question, it seems you cannot get this part working:
> Discard the nums[i-k]
element from the priority queue, and push into the queue nums[i]
Using Go's heap
, to modify an item (with heap.Fix
) or remove one (with heap.Remove
, an index to that item is required. To get the corresponding index, there are at least two ways.
Note that we need to distinguish from the indices of elements in nums
and the indices of elements in the queue. I am to refer to the former one as i
in the following code and the latter, j
. We know the i
of the element we want to remove, but since heap
changes the queue, we need to find j
.
Loop through the queue and find the element
Simple enough. In this way, you may just simplify the PriorityQueue
type:
type PriorityQueue []int
// I will skip the heap.Interface part
func maxSlidingWindow(nums []int, k int) []int {
pq := make(PriorityQueue, k)
result := make([]int, 0, len(nums)-k+1)
for i := 0; i < k; i++ { // 1.
pq[i] = nums[i]
}
heap.Init(&pq)
result = append(result, pq[0]) // 2.
for i := k; i < len(nums); i++ {
for j, value := range pq { // 3.1.
if value == nums[i-k] {
pq[j] = nums[i] // Instead of removing then pushing
heap.Fix(&pq, j) // We modify the content with heap.Fix
break
}
}
result = append(result, pq[0]) // 3.2.
}
return result
}
It handles duplicate values correctly.
Keep a external i -> j
mapping
Below is just a possible way doing it and may not be that elegant. I use a CircularArray
to keep our mapping:
type CircularArray []int
func (a CircularArray) wrapped(index int) int {
return index % len(a)
}
func (a CircularArray) Get(index int) int {
return a[a.wrapped(index)]
}
func (a CircularArray) Set(index int, value int) {
a[a.wrapped(index)] = value
}
func (a CircularArray) Swap(i, j int) {
ii, jj := a.wrapped(i), a.wrapped(j)
a[ii], a[jj] = a[jj], a[ii]
}
type PriorityQueue struct {
Window []int // The queue
IndicesOfIndices CircularArray // `i -> j` mapping
}
// func (pq *PriorityQueue) Len() ...
func (pq *PriorityQueue) Push(x interface{}) {} // don't use
func (pq *PriorityQueue) Pop() interface{} { return nil } // don't use
func (pq *PriorityQueue) Less(a, b int) bool {
return pq.Window[a] > pq.Window[b]
}
func (pq *PriorityQueue) Swap(a, b int) {
pq.Window[a], pq.Window[b] = pq.Window[b], pq.Window[a]
pq.IndicesOfIndices.Swap(a, b)
}
func maxSlidingWindow(nums []int, k int) []int {
pq := PriorityQueue{
Window: make([]int, 0, k),
IndicesOfIndices: make(CircularArray, k),
}
result := make([]int, 1, len(nums)-k+1)
for i := 0; i < k; i++ {
pq.PushWithIndex(nums[i], i) // 1.
}
heap.Init(&pq)
result[0] = pq.Window[0] // 2.
for i := k; i < len(nums); i++ {
result = append(result, pq.NextWithIndex(nums[i], i)) // 3.
}
return result
}
// Pushes into the queue and sets up the `i -> j` mapping
func (pq *PriorityQueue) PushWithIndex(value int, i int) {
pq.IndicesOfIndices.Set(i, len(pq.Window))
pq.Window = append(pq.Window, value)
}
// Updates the queue and returns the max element
func (pq *PriorityQueue) NextWithIndex(pushed int, i int) int {
j := pq.IndicesOfIndices.Get(i) // 3.1.
pq.Window[j] = pushed
heap.Fix(pq, j)
return pq.Window[0] // 3.2.
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论