技巧
堆 贪心
思路
如何贪心?
如果缓存区满了并且当前元素缓存里面不存在。 那么需要感知到当前缓存里面最远再次需要使用的元素进行淘汰。
如何实现?
用堆记录着元素下次出现的位置i 作为大根堆的权重 那么每次只需要要对堆顶做文章即可
实现
package main
import (
"bufio"
. "fmt"
"io"
"os"
"strconv"
"strings"
)
type Cache struct {
nextIndex, num, pos int
}
func siftUp(heap []*Cache, index int) {
for index != 0 && heap[index].nextIndex > heap[(index-1)/2].nextIndex {
heap[index].pos, heap[(index-1)/2].pos = heap[(index-1)/2].pos, heap[index].pos
heap[index], heap[(index-1)/2] = heap[(index-1)/2], heap[index]
index = (index - 1) / 2
}
}
func siftDown(heap []*Cache, last int) {
curr := 0
for curr*2+1 < last {
max := curr
if heap[curr*2+1].nextIndex > heap[curr].nextIndex {
max = curr*2 + 1
}
if curr*2+2 < last && heap[curr*2+2].nextIndex > heap[max].nextIndex {
max = curr*2 + 2
}
if max == curr {
break
}
heap[curr].pos, heap[max].pos = heap[max].pos, heap[curr].pos
heap[curr], heap[max] = heap[max], heap[curr]
curr = max
}
}
// 获取i后一个位置
func getNextIndex(tmp map[int][]int, num int, i int) int {
if i == int(^uint(0)>>1) {
return int(^uint(0) >> 1)
}
l, r := 0, len(tmp[num])-1
for l <= r {
mid := l + (r-l)/2
if tmp[num][mid] <= i {
l = mid + 1
} else {
r = mid - 1
}
}
if l == len(tmp[num]) {
return int(^uint(0) >> 1)
}
return tmp[num][l]
}
// https://ac.nowcoder.com/acm/problem/20185
func NC20185(_r io.Reader, _w io.Writer) {
in, out := bufio.NewReader(_r), bufio.NewWriter(_w)
defer out.Flush()
line1, _ := in.ReadString('\n')
line1 = strings.Trim(line1, "\n")
line2, _ := in.ReadString('\n')
line2 = strings.Trim(line2, "\n")
first := strings.Split(line1, " ")
second := strings.Split(line2, " ")
n, _ := strconv.Atoi(first[0])
m, _ := strconv.Atoi(first[1])
arr := make([]int, n)
tmp := make(map[int][]int) // 每个元素的索引位置
for i := 0; i < n; i++ {
num, _ := strconv.Atoi(second[i])
arr[i] = num
if _, ok := tmp[arr[i]]; ok {
tmp[arr[i]] = append(tmp[arr[i]], i)
} else {
tmp[arr[i]] = []int{i}
}
}
ans := 0
heap, lastIndex := make([]*Cache, m), 0 // 大根堆
currHeapCache := make(map[int]*Cache) // 缓存 (O1) 复杂度 这里不做缓存AC不掉
for i := 0; i < n; i++ {
// 如果已经在缓存中存在
if c, ok := currHeapCache[i]; ok {
delete(currHeapCache, c.nextIndex)
c.nextIndex = getNextIndex(tmp, arr[i], i) // 更新下一个位置
currHeapCache[c.nextIndex] = c
siftUp(heap, c.pos)
} else {
if lastIndex == m { // 淘汰堆顶
delete(currHeapCache, heap[0].nextIndex)
heap[0] = &Cache{getNextIndex(tmp, arr[i], i), arr[i], 0}
currHeapCache[heap[0].nextIndex] = heap[0]
siftDown(heap, lastIndex)
} else {
// 堆还没满
heap[lastIndex] = &Cache{getNextIndex(tmp, arr[i], i), arr[i], lastIndex}
currHeapCache[heap[lastIndex].nextIndex] = heap[lastIndex]
siftUp(heap, lastIndex)
lastIndex++
}
ans++
}
}
Fprintln(out, ans)
}
func main() {
NC20185(os.Stdin, os.Stdout)
}

京公网安备 11010502036488号