魔塔游戏

1.题目

这道题是2024-2-6的签到题,题目难度中等。

考核的知识点为:贪心算法+优先队列。

题目链接:魔塔游戏

小扣当前位于魔塔游戏第一层,共有 N 个房间,编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于数组 nums,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减少对应数值;0 表示房间对血量无影响。

小扣初始血量为 1,且无上限。假定小扣原计划按房间编号升序访问所有房间补血/打怪,为保证血量始终为正值,小扣需对房间访问顺序进行调整,每次仅能将一个怪物房间(负数的房间)调整至访问顺序末尾。请返回小扣最少需要调整几次,才能顺利访问所有房间。若调整顺序也无法访问完全部房间,请返回 -1。

2.思路

其实对于优先队列的问题,它其实已经包含了贪心算法的思想在里面,这道题也不例外。对于这道题,我们需要弄明白下面几个问题:

什么是优先队列?

优先队列相比于普通的队列,它会根据某种规则自动排序,比如根据队列元素的大小进行排序,小的在前面或者大的在前面。

通俗来讲,也有一个结构和它类似——小根堆。小根堆的特性是元素小的在上面,元素大的在下面(这里仅按照元素大小排序)。

如何应用到这题?

那我们如何使用优先队列在这题呢?根据题目要求,我们不到万不得已的时候不会移动怪物房间,因此我们只需要在当前的血量小于1的时候移动怪物房间,那移动哪一个怪物房间呢?这就提到我们的优先队列了,我们将扣血最多的怪物房间移动到队列尾部就行了,这样就即解决我们的血量问题,也能够使得利益最大化(贪心思想)。

解题思路

在我们对有限队列有了一定的认知后,我们在想怎么应用这题。我的思路是这样,这题的要求是尽可能最小移动次数来使得怪物房间移动到队尾。因此我们需要考虑两种情况:

  1. nums数组和小于0
  2. nums数组和大于0

对于第一种情况相信我们很容易理解,你都总和小于0了,说明无论怎么花里胡哨的移动,他最终都会ganmeover。

因此我们的算法只需要考虑第二种情况。首先,我们初始并定义一个小根堆,然后定义一个遍历blood作为血量,ans为操作次数。然后开始遍历数组,如果当前的num值小于0,说明这个房间是怪物房间,我们将它加入到小根堆(优先队列)里面。然后先加入到当前血量中,如果加入到当前血量后小于1,说明有个怪物房间需要移动到队尾了,因此这里需要移动扣血最多的怪物房间到队尾。

3.代码

import heapq
from typing import List
class S:
     def f(self,nums:List[int])->int:
          # 如果数组总和小于0,则返回-1
          if sum(nums) < 0:
               return -1
          # 操作次数
          ans = 0
          # 小根堆
          q = []
          # 血量
          blood = 1
          # 初始化为小根堆
          heapq.heapify(q)
          # 遍历nums数组
          for num in nums:
               # 如果当前的值小于0,则加入小根堆
               if num < 0:
                    heapq.heappush(q,num)
               # 加入到血量
               blood += num
               # 如果血量小于1,说明需要移动房间
               if blood < 1:
                    # 移动扣血最多的房间
                    blood -= heapq.heappop(q)
                    # 操作次数+1
                    ans += 1
          return ans

你可能感兴趣的:(算法解析,算法,数据结构,python)