1962. 移除石子使总数最小

1962. 移除石子使总数最小

1962. 移除石子使总数最小

难度中等

给你一个整数数组 piles ,数组 下标从 0 开始 ,其中 piles[i] 表示第 i 堆石子中的石子数量。另给你一个整数 k ,请你执行下述操作 恰好 k 次:

  • 选出任一石子堆 piles[i] ,并从中 移除 floor(piles[i] / 2) 颗石子。

注意: 你可以对 同一堆 石子多次执行此操作。

返回执行 k 次操作后,剩下石子的 最小 总数。

floor(x)小于等于 x最大 整数。(即,对 x 向下取整)。

示例 1:

输入: piles = [5,4,9], k = 2 输出: 12 解释: 可能的执行情景如下:

  • 对第 2 堆石子执行移除操作,石子分布情况变成 [5,4, 5 ] 。
  • 对第 0 堆石子执行移除操作,石子分布情况变成 [ 3 ,4,5] 。 剩下石子的总数为 12 。

示例 2:

输入: piles = [4,3,6,7], k = 3 输出: 12 解释: 可能的执行情景如下:

  • 对第 2 堆石子执行移除操作,石子分布情况变成 [4,3, 3 ,7] 。
  • 对第 3 堆石子执行移除操作,石子分布情况变成 [4,3,3, 4 ] 。
  • 对第 0 堆石子执行移除操作,石子分布情况变成 [ 2 ,3,3,4] 。 剩下石子的总数为 12 。

提示:

  • 1 <= piles.length <= 105
  • 1 <= piles[i] <= 104
  • 1 <= k <= 105

函数签名:

func minStoneSum(piles []int, k int) int

分析

贪心+大顶堆

每次消除最大一堆石头的一半即可。

func minStoneSum(piles []int, k int) int {
    h := &Heap{piles}
    h.init()
    for ; k > 0 && h.peek() > 1; k-- {
        cur := h.pop()
        h.push(cur - cur/2)
    }
    sum := 0
    for _, v := range h.data {
        sum += v
    }
    return sum
}

type Heap struct {
    data []int
}

func (h *Heap) Len() int           { return len(h.data) }
func (h *Heap) Less(i, j int) bool { return h.data[i] > h.data[j] }
func (h *Heap) Swap(i, j int)      { h.data[i], h.data[j] = h.data[j], h.data[i] }
func (h *Heap) Push(x interface{}) { h.data = append(h.data, x.(int)) }
func (h *Heap) Pop() interface{} {
    n := len(h.data)
    x := h.data[n-1]
    h.data = h.data[:n-1]
    return x
}
func (h *Heap) init() {heap.Init(h)}
func (h *Heap) push(x int) { heap.Push(h, x) }
func (h *Heap) pop() int   { return heap.Pop(h).(int) }
func (h *Heap) peek() int  { return h.data[0] }

时间复杂度:O(n+klogn),空间复杂度:O(n)