LeetCode】每日一题 2023_12_23 移除石子使总数最小(堆)(含 go 如何实现堆以及 heap 的使用)

文章目录

  • 刷题前唠嗑
  • 题目:移除石子使总数最小
    • 题目描述
    • 代码与解题思路

刷题前唠嗑

LeetCode】每日一题 2023_12_23 移除石子使总数最小(堆)(含 go 如何实现堆以及 heap 的使用)_第1张图片
LeetCode?启动!!!

每日一题重返战场

题目:移除石子使总数最小

题目链接:1962. 移除石子使总数最小

题目描述

LeetCode】每日一题 2023_12_23 移除石子使总数最小(堆)(含 go 如何实现堆以及 heap 的使用)_第2张图片

代码与解题思路

func minStoneSum(piles []int, k int) (ans int) {
    h := &hp{piles}
    heap.Init(h)
    for ; k > 0 && piles[0] != 0; k-- {
        piles[0] -= piles[0]/2 // 修改堆顶
        heap.Fix(h, 0) // 向下调整
    }
    for _, x := range piles {
        ans += x
    }
    return ans
}

type hp struct {arr []int}
func (h hp) Swap(i, j int) { h.arr[i], h.arr[j] = h.arr[j], h.arr[i] } 
func (h hp) Less(i, j int) bool { return h.arr[i] > h.arr[j] } // 建大堆
func (h hp) Len() int { return len(h.arr)}
func (hp) Pop() (_ any) { return }
func (hp) Push(any) {}

我们可以通过将题目给的数组建成一个大堆,然后通过修改每次修改堆顶,就能实现题目每次修改数组的最大值的要求了,然后修改 k 次,最后再求数组值的和返回即可

想念 C++ 的 priority_queue 了,go 的 heap 使用起来真的是折磨,他需要:

  1. 实现一个 hp 结构体,或者数组,用于存储堆的值
  2. 然后实现 Swap,Less,Len,Pop,Push 整整五个方法,一个都不能少,我的建议是不如直接自己实现一个堆算了

说干就干:

func minStoneSum(piles []int, k int) (ans int) {
    n := len(piles)
    buildMaxHeap(piles, n)
    for ; k > 0 && piles[0] != 0; k-- {
        piles[0] -= piles[0]/2 // 修改堆顶
        AdjustDown(piles, n, 0) // 向下调整
    }
    for _, x := range piles {
        ans += x
    }
    return ans
}

func buildMaxHeap(nums []int, n int) { // 建一个大堆
    for i := (n-2)/2; i >= 0; i-- { // 不需要遍历叶子节点(如果不明白就画个图)
        AdjustDown(nums, n, i)
    }
}

func AdjustDown(nums []int, n, parent int) { // 向下调整操作
    child := parent*2+1 // (左孩子)子节点 = 父节点 * 2 + 1, 右孩子是 * 2 + 2
    for child < n { // 子节点需要在堆(数组)的范围内
        if (child+1) < n && nums[child+1] > nums[child] { // 比较左右孩子大小
            child++ // 右孩子大, 那就往右孩子那边调整
        }
        if nums[child] > nums[parent] { // 如果子节点大于父节点, 就交换
            swap(&nums[child], &nums[parent]);
            parent = child // child 作为新的父节点
            child = parent*2+1 // 找下一个孩子
        } else {
            break // 这部分已经是大堆了
        }
    }
}

func swap(a, b *int) {
    *a, *b = *b, *a
}

舒服了,如果不知道怎么建堆,可以看,数组中的第K个最大元素:建堆的详细解析

你可能感兴趣的:(LeetCode,每日一题,leetcode,golang,算法)