题目
小扣当前位于魔塔游戏第一层,共有 N 个房间,编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于数组 nums,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减少对应数值;0 表示房间对血量无影响。
小扣初始血量为 1,且无上限。假定小扣原计划按房间编号升序访问所有房间补血/打怪,为保证血量始终为正值,小扣需对房间访问顺序进行调整,每次仅能将一个怪物房间(负数的房间)调整至访问顺序末尾。请返回小扣最少需要调整几次,才能顺利访问所有房间。若调整顺序也无法访问完全部房间,请返回 -1。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/p0NxJO
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例
思路
本题与871.最低加油次数思路一模一样
链接:https://leetcode.cn/problems/minimum-number-of-refueling-stops/solution/chun-by-xun-ge-v-efe1/
针对本题,我们可以动态规划,也可以贪心结合优先队列
对于优先队列可以用最小堆,也可以自制一个优先队列,定义一个数组保存经过的血量,可能为负,再对这个数组进行简单处理,我们每存一个元素,就对数组进行升序排序(快速排序),那么靠后面的就是最小的血量
我们一路向前,将经过的血量为负值保存在数组中,当hp为负值时,到数组中取最小值,进行回血,同时保存回血的值,后面还是要克的,反复上述操作,最后将hp和回血的值进行比较
代码
int cmp(const void * a, const void * b)
{
return *(int *)b - *(int *)a;
}
int magicTower(int* nums, int numsSize){
int * ans = malloc(sizeof(int) * numsSize);//定义简易队列
int right = 0;
int i = 0;
long sum = 0;
int n = 0;
long hp = 1;
for(i = 0; i < numsSize; i++)//遍历房间
{
if(nums[i] < 0)//血量为负,存储到队列中
{
ans[right++] = nums[i];
}
hp += nums[i];//打完这个怪,判断是否血量不健康
if(hp <= 0)//不健康,把之前血量最厚的怪恢复
{
qsort(ans, right, sizeof(ans[0]), cmp);
n++;
hp += abs(ans[right-1]);
sum += ans[right-1];//保存所有恢复怪的血量,后面再打
right--;
}
}
if((hp + sum) <= 0)//最后还是打不过
{
return -1;
}
return n;
}
时间空间复杂度