[Leetcode解題] 3186. Maximum Total Damage With Spell Casting

11 October 2025
medium dp

3186. Maximum Total Damage With Spell Casting

題目

3186. Maximum Total Damage With Spell Casting

題目給一個整數陣列 power,代表了一系列法術的傷害值。您可以施放任意數量的法術,但有一個重要的限制:

如果施放了一個傷害值為 p 的法術,那麼就不能再施放傷害值為 p-1、p-2、p+1 或 p+2 的法術。

目標是,在遵守這個規則的前提下,最大化您能造成的總傷害。

舉個例子: 假設 power = [1, 1, 3, 4]

如果選擇傷害為 4 的法術,總傷害是 4。那就不能再選 3 了。接著可以選 1,因為 1 和 4 的差大於 2。所以可以選兩個 1。總傷害是 4 + 1 + 1 = 6。

如果選擇傷害為 3 的法術,總傷害是 3。那就不能選 1 和 4。總傷害就是 3。

比較之下,最大總傷害是 6。

解題思路

這題我們先計算每個法術傷害值出現的次數,並且用一個hashset來表示所有不同傷害值的法術,再進行sort由大排到小

接下來使用dp求解,dp存放的是,考慮到該法術時,能造成的最大傷害為何?

所以每次做的時候,可以施放該法術,或者不施放法術,來求得當前的dp值

如果施放法術p,那麼當前的dp值為

dp[i] = p * counts[p] + dp[last_p_idx]

last_p_idx為上一個在法術限制範圍外,可施放法術的索引,我們要取得他的dp值

如果不施放法術p,那dp值即為上一個法術的dp值(考慮到i-1),最後取兩者最大的值

dp[i] = max(take_p, not_take_p)

程式碼

class Solution:
    def maximumTotalDamage(self, power: List[int]) -> int:
        counts = Counter(power)
        unique_power = sorted(counts.keys())
        
        n = len(unique_power)
        dp = [0] * n

        for i in range(n):
            p = unique_power[i]
            current_damage = p * counts[p]

            last_p_idx = -1
            for j in range(i-1, -1, -1):
                if unique_power[j] < p - 2:
                    last_p_idx = j
                    break
            
            take_p = current_damage + dp[last_p_idx] if last_p_idx != -1 else current_damage

            not_take_p = dp[i-1] if i >= 1 else 0

            dp[i] = max(take_p, not_take_p)
        return dp[-1]

時間複雜度

遍歷過一遍,但有做sort,所以為$O(n log n)$,$n$為不重複法術傷害的數量