题解 | #Running Median#
Running Median
https://ac.nowcoder.com/acm/problem/50940
技巧
对顶堆
思路
小根堆保存较大的一侧 | 大根堆保存较小的一侧
if element <= 小根堆(顶) => 插入大根堆
else 插入小根堆
两个堆平衡调整 |h1Last - h2Last| <= 1 (如果不平衡就调整成平衡的)
每次取多的那个堆顶元素就是中位数
实现
package main
import (
"bufio"
. "fmt"
"io"
"os"
)
func siftDown(h []int, bigHeap bool, end int) {
curr := 0
if bigHeap {
for curr < end {
max := curr
l, r := 2*curr+1, 2*curr+2
if l < end {
if h[l] > h[max] {
max = l
}
if r < end && h[r] > h[max] {
max = r
}
}
if max == curr {
break
}
h[curr], h[max] = h[max], h[curr]
curr = max
}
} else {
for curr < end {
min := curr
l, r := 2*curr+1, 2*curr+2
if l < end {
if h[l] < h[min] {
min = l
}
if r < end && h[r] < h[min] {
min = r
}
}
if min == curr {
break
}
h[curr], h[min] = h[min], h[curr]
curr = min
}
}
}
func siftUp(h []int, bigHeap bool, last int) {
i := last
if bigHeap {
for i > 0 && h[i] > h[(i-1)/2] {
h[i], h[(i-1)/2] = h[(i-1)/2], h[i]
i = (i - 1) / 2
}
} else {
for i > 0 && h[i] < h[(i-1)/2] {
h[i], h[(i-1)/2] = h[(i-1)/2], h[i]
i = (i - 1) / 2
}
}
}
// https://ac.nowcoder.com/acm/problem/16663
func NC50940(_r io.Reader, _w io.Writer) {
in, out := bufio.NewReader(_r), bufio.NewWriter(_w)
defer out.Flush()
var P int
for Fscan(in, &P); P > 0; P-- {
var id, cnt int
Fscan(in, &id, &cnt)
var printCnt = 1
// 小根堆存大的一半 大根堆存小的那一部分
h1, h2 := make([]int, cnt/2+1), make([]int, cnt/2+1)
h1Last, h2Last := 0, 0
Fprintln(out, id, cnt/2+1)
for i := 1; i <= cnt; i++ {
var e int
Fscan(in, &e)
// 插入策略
if h1Last == 0 {
h1[h1Last] = e
h1Last++
} else {
if e <= h1[0] {
h2[h2Last] = e
siftUp(h2, true, h2Last)
h2Last++
} else {
h1[h1Last] = e
siftUp(h1, false, h1Last)
h1Last++
}
}
var tmp int
// 平衡调整
if h1Last-h2Last > 1 {
tmp = h1[0]
h1[0] = h1[h1Last-1]
siftDown(h1, false, h1Last-1)
h1Last--
h2[h2Last] = tmp
siftUp(h2, true, h2Last)
h2Last++
} else if h2Last-h1Last > 1 {
tmp = h2[0]
h2[0] = h2[h2Last-1]
siftDown(h2, true, h2Last-1)
h2Last--
h1[h1Last] = tmp
siftUp(h1, false, h1Last)
h1Last++
}
// 输出
if i%2 != 0 {
if h1Last > h2Last {
if printCnt%10 == 1 {
if printCnt > 10 {
Fprintln(out)
}
Fprint(out, h1[0])
} else {
Fprint(out, " ", h1[0])
}
} else {
if printCnt%10 == 1 {
if printCnt > 10 {
Fprintln(out)
}
Fprint(out, h2[0])
} else {
Fprint(out, " ", h2[0])
}
}
printCnt++
}
}
Fprintln(out)
}
}
func main() {
NC50940(os.Stdin, os.Stdout)
}
查看13道真题和解析

