Leetcode LCP30 魔塔游戏
LCP30.魔塔游戏
小扣当前位于魔塔游戏第一层,共有 N
个房间,编号为 0 ~ N-1
。每个房间的补血道具/怪物对于血量影响记于数组 nums
,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减少对应数值;0
表示房间对血量无影响。
小扣初始血量为 1,且无上限。假定小扣原计划按房间编号升序访问所有房间补血/打怪,为保证血量始终为正值,小扣需对房间访问顺序进行调整,每次仅能将一个怪物房间(负数的房间)调整至访问顺序末尾。请返回小扣最少需要调整几次,才能顺利访问所有房间。若调整顺序也无法访问完全部房间,请返回 -1。
示例 1:
输入: nums = [100,100,100,-250,-60,-140,-50,-50,100,150]
输出: 1
解释: 初始血量为 1。至少需要将 nums[3]
调整至访问顺序末尾以满足要求.
示例 2:
输入: nums = [-200,-300,400,0]
输出: -1
解释: 调整访问顺序也无法完成全部房间的访问。
提示:
1 <= nums.length <= 10^5
-10^5 <= nums[i] <= 10^5
Related Topics
- 贪心
- 数组
- 堆(优先队列)
题目链接: link
解答
本题的难度是 Medium.
这里的话我们可以考虑贪心算法, 从左到右遍历, 如果当前的血量小于 0 我们才考虑调整. 那这边我们当然是希望如果能够调整当然是能调整次数越少越好, 因此肯定选择把前面扣血最多的负数移到最后面, 因此其实我们相当于是需要维护一个最小堆, 因为只有负值才会放到堆里. 这样我们就可以每次取出堆顶的元素, 然后把血量加上这个值, 然后再把这个值放到最后面. 这样我们就可以得到最少需要调整的次数了. 在 Java 里面有一个小根堆的实现, 就是 PriorityQueue
, 这个类默认是小根堆, 因此我们可以直接使用这个类.
代码如下:
class Solution {
public int magicTower(int[] nums) {
long temp =0;
int n = nums.length;
for (int i = 0; i < n; i++) {
temp += nums[i];
}
if (temp<0){return -1;}
PriorityQueue<Integer> pq = new PriorityQueue<>();
int result = 0;
temp = 0;
for (int i = 0; i < n; i++) {
temp += nums[i];
if (nums[i] < 0) {
pq.offer(nums[i]);
}
if (temp < 0){
temp -= pq.poll();
result++;
}
}
return result;
}
}
时间开销为 10ms, 击败了 70% 的提交, 但是实际上很抽象啊, 我看了 9ms 的代码, 和我的基本一模一样. 这里有一些可能看起来会有疑虑的, 比如我 poll 之后其实就移除了这个元素, 难道不需要移到最后面吗?这里其实是因为我们一开始就判断了能不能成, 因为能成的话其实移到最后的负数是可以不用关心的, 因为只是结果是一定能达到的, 我们只需要适当调整过程就行了.
我看题解还有反悔贪心, 我一开始还奇怪什么叫反悔贪心, 原来就是先一直过过过过, 一个都不调整, 然后不行了, 这时候反悔, 我要调整了!然后调整还是按贪心, 要调整就调整能够影响最多的. 看起来和我的代码是一样的.
如果要大根堆的话, 稍微改变就行了
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());