Skip to content

Files

Latest commit

c29b144 · May 17, 2024

History

History
197 lines (160 loc) · 5.39 KB

README.md

File metadata and controls

197 lines (160 loc) · 5.39 KB
comments difficulty edit_url
true
中等

题目描述

小扣当前位于魔塔游戏第一层,共有 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

解法

方法一:贪心 + 优先队列(小根堆)

我们定义以下数据结构或变量,其中:

  • 优先队列(小根堆) q :存储当前所有怪物房间的血量减少值,堆顶元素为血量减少值最大的怪物房间(也即是最小的负数)。
  • 血量 b l o o d :存储当前的血量,初始时 b l o o d = 1
  • 操作次数 a n s :存储已经进行的操作次数,初始时 a n s = 0
  • 临时变量 v :存储当前待减少的血量,初始时 v = 0

我们按照房间编号升序遍历所有房间,对于当前遍历到的房间 x ,如果 x 为怪物房间,我们就将 x 的血量减少值加入 q 。然后,我们更新当前的血量 b l o o d ,即 b l o o d = b l o o d + x 。如果此时 b l o o d 0 ,说明当前的血量不足以通过当前房间,因此我们需要调整访问顺序,此时我们可以贪心地将 q 中血量减少值最大的房间调整至访问顺序的末尾,即把它累加到临时变量 v 上,然后将 b l o o d 增加对应的值,并将该房间从 q 中弹出。

遍历结束后,我们需要更新当前的血量 b l o o d ,即 b l o o d = b l o o d + v 。如果此时 b l o o d 0 ,说明无法访问完所有房间,返回 1 。否则,返回 a n s

时间复杂度 O ( n × log n ) ,空间复杂度 O ( n ) ,其中 n 为房间的数量。

Python3

class Solution:
    def magicTower(self, nums: List[int]) -> int:
        q = []
        blood = 1
        ans = v = 0
        for x in nums:
            if x < 0:
                heappush(q, x)
            blood += x
            if blood <= 0:
                ans += 1
                v += q[0]
                blood -= heappop(q)
        blood += v
        return -1 if blood <= 0 else ans

Java

class Solution {
    public int magicTower(int[] nums) {
        PriorityQueue<Integer> q = new PriorityQueue<>();
        long blood = 1, v = 0;
        int ans = 0;
        for (int x : nums) {
            if (x < 0) {
                q.offer(x);
            }
            blood += x;
            if (blood <= 0) {
                ++ans;
                v += q.peek();
                blood -= q.poll();
            }
        }
        blood += v;
        return blood <= 0 ? -1 : ans;
    }
}

C++

class Solution {
public:
    int magicTower(vector<int>& nums) {
        priority_queue<int, vector<int>, greater<int>> q;
        int64_t blood = 1, v = 0;
        int ans = 0;
        for (int x : nums) {
            if (x < 0) {
                q.push(x);
            }
            blood += x;
            if (blood <= 0) {
                ++ans;
                v += q.top();
                blood -= q.top();
                q.pop();
            }
        }
        blood += v;
        return blood <= 0 ? -1 : ans;
    }
};

Go

func magicTower(nums []int) (ans int) {
	q := hp{}
	blood, v := 1, 0
	for _, x := range nums {
		if x < 0 {
			heap.Push(&q, x)
		}
		blood += x
		if blood <= 0 {
			ans++
			t := heap.Pop(&q).(int)
			v += t
			blood -= t
		}
	}
	if blood+v <= 0 {
		return -1
	}
	return ans
}

type hp struct{ sort.IntSlice }

func (h hp) Less(i, j int) bool { return h.IntSlice[i] < h.IntSlice[j] }
func (h *hp) Push(v any)        { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() any {
	a := h.IntSlice
	v := a[len(a)-1]
	h.IntSlice = a[:len(a)-1]
	return v
}

TypeScript

function magicTower(nums: number[]): number {
    const q = new MinPriorityQueue();
    let [ans, blood, v] = [0, 1, 0];
    for (const x of nums) {
        if (x < 0) {
            q.enqueue(x);
        }
        blood += x;
        if (blood <= 0) {
            ++ans;
            const t = q.dequeue().element;
            blood -= t;
            v += t;
        }
    }
    return blood + v <= 0 ? -1 : ans;
}