LeetCode-2558. 从数量最多的堆取走礼物-大顶堆

Problem: 2558. 从数量最多的堆取走礼物
每日一题。

思路

找最大,对最大值求平方根+求和。下意识在原数组直接改动,后联系大顶堆(任意结点>=其子节点)

Code

图一乐(排序操作)

从小到大排序,对末尾下标操作。

    public long pickGifts(int[] gifts, int k) {
        long sum = 0;
        for (int i = gifts.length - 1; i >= gifts.length - k; i--) {
            Arrays.sort(gifts);// 排序
            gifts[gifts.length - 1] = (int) Math.floor(Math.sqrt(gifts[gifts.length - 1]));// 下标操作
        }
        for (int i : gifts) {
            sum += (long) i;
        }
        return sum;
    }

大顶堆


class Solution {
    public long pickGifts(int[] gifts, int k) {
        long sum = 0;
        // 实例化堆并写入
        Queue<Integer> queue = new PriorityQueue<>((a,b)->(b-a));// 默认小顶堆
        for (int i : gifts) {
            queue.offer(i);
        }
        for (int i = 0; i < k; i++) {
            int max = (int) queue.poll();// 获取堆顶
            int sqrt = (int) Math.floor(Math.sqrt(max));
            queue.offer(sqrt);
        }
        for (Integer i : queue) {
            sum += i;
        }
        return sum;
    }
}

原地堆化(灵神的代码)

原地址
添加了部分注释。

    public long pickGifts(int[] gifts, int k) {
        heapify(gifts); // 原地堆化(大顶堆)
        // 判断堆顶是否为1,节省运行时间,不判断会进入下沉方法中退出。
        while (k-- > 0 && gifts[0] > 1) {
            gifts[0] = (int) Math.sqrt(gifts[0]); // 直接修改堆顶
            // 下沉方法
            sink(gifts, 0); // 堆化(只需要把 gifts[0] 下沉)
        }

        long ans = 0;
        for (int x : gifts) {
            ans += x;
        }
        return ans;
    }

    // 原地堆化(大顶堆)
    // 堆化可以保证 h[0] 是堆顶元素,且 h[i] >= max(h[2*i+1], h[2*i+2])
    private void heapify(int[] h) {
        // h.length / 2 - 1 倒着遍历,保证堆结构
        for (int i = h.length / 2 - 1; i >= 0; i--) {
            sink(h, i);
        }
    }

    // 下沉方法
    private void sink(int[] h, int i) {
        int n = h.length;
        while (2 * i + 1 < n) {
            int j = 2 * i + 1; // i 的左儿子
            if (j + 1 < n && h[j + 1] > h[j]) { // i 的右儿子比 i 的左儿子大
                j++;
            }
            if (h[j] <= h[i]) { // 说明 i 的左右儿子都 <= h[i],停止下沉
                break;
            }
            swap(h, i, j); // 下沉
            i = j;
        }
    }

    // 交换 h[i] 和 h[j]
    private void swap(int[] h, int i, int j) {
        int tmp = h[i];
        h[i] = h[j];
        h[j] = tmp;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值