题目:
给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。你的 起始分数 为 0 。
在一步 操作 中:
- 选出一个满足
0 <= i < nums.length的下标i, - 将你的 分数 增加
nums[i],并且 - 将
nums[i]替换为ceil(nums[i] / 3)。
返回在 恰好 执行 k 次操作后,你可能获得的最大分数。
向上取整函数 ceil(val) 的结果是大于或等于 val 的最小整数。
算法:
方法一:大顶堆
func maxKelements(nums []int, k int) int64 {
heap := NewHeap(nums)
ans := int64(0)
for i := 0; i < k; i ++ {
n := heap.Pop()
ans = ans + int64(n)
heap.Push(ceil(n))
}
return ans
}
func ceil(n int) int {
if n % 3 == 0 {
return n / 3
}
return n / 3 + 1
}
type Heap struct {
heap []int
}
func NewHeap(nums []int) *Heap {
h := Heap{make([]int, 1)}
for i := range nums {
h.Push(nums[i])
}
return &h
}
func (h *Heap) Length() int {
// fmt.Println(h.heap)
return len(h.heap) - 1
}
func (h *Heap) Push(x int) {
h.heap = append(h.heap, x)
h.up(len(h.heap) - 1)
}
func (h *Heap) Pop() int {
n := len(h.heap)
x := h.heap[1]
h.heap[1], h.heap[n - 1] = h.heap[n - 1], h.heap[1]
h.heap = h.heap[:n - 1]
h.sink(1)
// fmt.Println("after pop", h.heap)
return x
}
func (h *Heap) sink(i int) {
child := 2 * i
// 先找到两个儿子中较大的,再和父亲比较,如果比父亲大,则交换位置
if child + 1 < len(h.heap) && h.heap[child + 1] > h.heap[child] {
child ++
}
if child < len(h.heap) && h.heap[i] < h.heap[child] {
h.heap[child], h.heap[i] = h.heap[i], h.heap[child]
h.sink(child)
}
}
func (h *Heap) up(i int) {
father := i / 2
if 0 < father && h.heap[father] < h.heap[i] {
h.heap[father], h.heap[i] = h.heap[i], h.heap[father]
h.up(father)
}
}