文章

[LeetCode] 每日一题 3066. 超过阈值的最少操作数 II

题目链接

https://leetcode.cn/problems/minimum-operations-to-exceed-threshold-value-ii

题目描述

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。

一次操作中,你将执行:

  • 选择 nums 中最小的两个整数 x 和 y 。

  • 将 x 和 y 从 nums 中删除。

  • 将 min(x, y) * 2 + max(x, y) 添加到数组中的任意位置。

注意,只有当 nums 至少包含两个元素时,你才可以执行以上操作。

你需要使数组中的所有元素都大于或等于 k ,请你返回需要的 最少 操作次数。

示例输入

示例 1

输入:nums = [2,11,10,1,3], k = 10
输出:2
解释:第一次操作中,我们删除元素 1 和 2 ,然后添加 1 * 2 + 2 到 nums 中,nums 变为 [4, 11, 10, 3] 。
第二次操作中,我们删除元素 3 和 4 ,然后添加 3 * 2 + 4 到 nums 中,nums 变为 [10, 11, 10] 。
此时,数组中的所有元素都大于等于 10 ,所以我们停止操作。
使数组中所有元素都大于等于 10 需要的最少操作次数为 2 。

示例 2

输入:nums = [1,1,2,4,9], k = 20
输出:4
解释:第一次操作后,nums 变为 [2, 4, 9, 3] 。
第二次操作后,nums 变为 [7, 4, 9] 。
第三次操作后,nums 变为 [15, 9] 。
第四次操作后,nums 变为 [33] 。
此时,数组中的所有元素都大于等于 20 ,所以我们停止操作。
使数组中所有元素都大于等于 20 需要的最少操作次数为 4 。

提示

  • 2 <= nums.length <= 2 * 10^5

  • 1 <= nums[i] <= 10^9

  • 1 <= k <= 10^9

  • 输入保证答案一定存在,也就是说一定存在一个操作序列使数组中所有元素都大于等于 k

解题思路

今天的这道题虽然和昨天的难度相似,实际上有一些细节值得注意,尤其是要从数组中删除最小的两个元素并进行操作。这个过程的核心思想是利用最小堆(优先队列),它能够保证我们每次操作时都能轻松找到最小的两个数

我的解法的关键是:

  1. 使用 PriorityQueue 来维护最小堆,使得每次操作都能取到最小的两个元素 xy

  2. 执行题目中的操作:计算 min(x, y) * 2 + max(x, y),并将结果重新插入堆中

  3. 不断执行这个操作,直到堆中的最小元素大于或等于 k

值得一提的是,在这个过程中,我最初遇到一个问题:数组的数值范围很大,nums[i]k 的最大值都可以达到 10^9,因此最初我使用了 Integer 类型。结果因为数据越界导致提交失败,经过查看题目范围后,我改用了 Long 类型,避免了溢出问题

此外,虽然题目中提到“将 min(x, y) * 2 + max(x, y) 添加到数组中的任意位置”,但是由于我们是从最小堆中取出两个元素,x 必然小于 y,所以直接用 x + x + y 来简化计算,避免了额外的判断逻辑。这个优化使得代码更加简洁且高效

代码实现

class Solution {
    public int minOperations(int[] nums, int k) {
        PriorityQueue<Long> queue = new PriorityQueue<>();
        int cnt = 0;
        for (int num : nums) {
            queue.offer(Long.valueOf(num));
        }
        while (queue.size() >= 2 && queue.peek() < k) {
            cnt++;
            long x = queue.poll();
            long y = queue.poll();
            queue.offer(x + x + y);
        }
        return cnt;
    }
}

复杂度分析

  • 时间复杂度O(n log n),其中 n 是数组 nums 的长度。每次操作从优先队列中删除两个元素并插入一个新的元素,时间复杂度为 O(log n)。由于最多执行 n 次操作,整体时间复杂度是 O(n log n)

  • 空间复杂度O(n),我们使用了一个优先队列来存储所有的元素,空间复杂度为 O(n)

总结

这道题虽然看起来比较简单,但处理数值范围大的问题时,我们要特别注意避免数据越界。在我自己的解决过程中,初次提交时就因为溢出错误没有通过,经过反思后选择了 Long 类型,顺利解决了问题。这也让我对题目给出的数据范围有了更加深刻的理解。在实际开发中,像这样的细节问题时常会遇到,只有细心才能避免低级错误

希望这篇分享能为你带来启发!如果你有任何问题或建议,欢迎在评论区留言,与我共同交流探讨。

License:  CC BY 4.0