Maximum Total Damage With Spell Casting
MediumUpdated: Oct 11, 2025
Practice on:
Problem
A magician has various spells.
You are given an array power, where each element represents the damage of a spell. Multiple spells can have the same damage value.
It is a known fact that if a magician decides to cast a spell with a damage of
power[i], they cannot cast any spell with a damage of power[i] - 2,
power[i] - 1, power[i] + 1, or power[i] + 2.
Each spell can be cast only once.
Return the maximum possible total damage that a magician can cast.
Examples
Example 1
Input: power = [1,1,3,4]
Output: 6
Explanation:
The maximum possible damage of 6 is produced by casting spells 0, 1, 3 with
damage 1, 1, 4.
Example 2
Input: power = [7,1,6,6]
Output: 13
Explanation:
The maximum possible damage of 13 is produced by casting spells 1, 2, 3 with
damage 1, 6, 6.
Constraints
1 <= power.length <= 10^51 <= power[i] <= 10^9
Solution
Method 1 – Dynamic Programming with Frequency Counting
Intuition
This problem is similar to the "House Robber" or "Delete and Earn" pattern, but with a wider forbidden range. For each unique damage value, if we cast spells of this damage, we must skip all spells with damage within 2 of it. We use dynamic programming to track the best total damage at each value.
Approach
- Count the frequency of each damage value in
power. - Sort the unique damage values.
- Use a DP array where
dp[i]is the max damage using up to theith unique value:- For each value, either:
- Skip it: take
dp[i-1]. - Take it: add its total damage to
dp[j], wherejis the last index with value at least 3 less than current.
- Skip it: take
- For each value, either:
- Return the last value in the DP array.
Complexity
- ⏰ Time complexity:
O(n log n)— Sorting and DP over unique values. - 🧺 Space complexity:
O(n)— For frequency and DP arrays.
Code
C++
class Solution {
public:
long long maximumTotalDamage(vector<int>& power) {
map<int, int> freq;
for (int x : power) freq[x]++;
vector<int> vals;
for (auto& [v, _] : freq) vals.push_back(v);
int n = vals.size();
vector<long long> dp(n);
for (int i = 0; i < n; ++i) {
long long dmg = 1LL * vals[i] * freq[vals[i]];
int j = i - 1;
while (j >= 0 && vals[j] >= vals[i] - 2) --j;
long long skip = (i ? dp[i-1] : 0LL);
long long take = dmg + (j >= 0 ? dp[j] : 0LL);
dp[i] = max(skip, take);
}
return dp.back();
}
};
Go
func maximumTotalDamage(power []int) int64 {
freq := map[int]int{}
for _, x := range power { freq[x]++ }
vals := []int{}
for v := range freq { vals = append(vals, v) }
sort.Ints(vals)
n := len(vals)
dp := make([]int64, n)
for i, v := range vals {
dmg := int64(v) * int64(freq[v])
j := i - 1
for j >= 0 && vals[j] >= v-2 { j-- }
var skip int64 = 0
if i > 0 { skip = dp[i-1] }
var take int64 = dmg
if j >= 0 { take += dp[j] }
if skip > take { dp[i] = skip } else { dp[i] = take }
}
return dp[n-1]
}
func max(a, b int) int { if a > b { return a } else { return b } }
Java
class Solution {
public long maximumTotalDamage(int[] power) {
Map<Integer, Integer> freq = new HashMap<>();
for (int x : power) freq.put(x, freq.getOrDefault(x, 0) + 1);
List<Integer> vals = new ArrayList<>(freq.keySet());
Collections.sort(vals);
int n = vals.size();
long[] dp = new long[n];
for (int i = 0; i < n; ++i) {
long dmg = 1L * vals.get(i) * freq.get(vals.get(i));
int j = i - 1;
while (j >= 0 && vals.get(j) >= vals.get(i) - 2) j--;
long skip = i > 0 ? dp[i-1] : 0L;
long take = dmg + (j >= 0 ? dp[j] : 0L);
dp[i] = Math.max(skip, take);
}
return dp[n-1];
}
}
Kotlin
class Solution {
fun maximumTotalDamage(power: IntArray): Long {
val freq = mutableMapOf<Int, Int>()
for (x in power) freq[x] = freq.getOrDefault(x, 0) + 1
val vals = freq.keys.sorted()
val n = vals.size
val dp = LongArray(n)
for (i in vals.indices) {
val dmg = vals[i].toLong() * freq[vals[i]]!!.toLong()
var j = i - 1
while (j >= 0 && vals[j] >= vals[i] - 2) j--
val skip = if (i > 0) dp[i-1] else 0L
val take = dmg + if (j >= 0) dp[j] else 0L
dp[i] = maxOf(skip, take)
}
return dp.last()
}
}
Python
def maximumTotalDamage(power: list[int]) -> int:
from collections import Counter
freq = Counter(power)
vals = sorted(freq)
n = len(vals)
dp = [0] * n
for i, v in enumerate(vals):
dmg = v * freq[v]
j = i - 1
while j >= 0 and vals[j] >= v - 2:
j -= 1
skip = dp[i-1] if i > 0 else 0
take = dmg + (dp[j] if j >= 0 else 0)
dp[i] = max(skip, take)
return dp[-1]
Rust
impl Solution {
pub fn maximum_total_damage(power: Vec<i32>) -> i64 {
use std::collections::HashMap;
let mut freq = HashMap::new();
for &x in &power { *freq.entry(x).or_insert(0) += 1; }
let mut vals: Vec<_> = freq.keys().cloned().collect();
vals.sort();
let n = vals.len();
let mut dp = vec![0i64; n];
for i in 0..n {
let dmg = vals[i] as i64 * freq[&vals[i]] as i64;
let mut j = i as i32 - 1;
while j >= 0 && vals[j as usize] >= vals[i] - 2 { j -= 1; }
let skip = if i > 0 { dp[i-1] } else { 0 };
let take = dmg + if j >= 0 { dp[j as usize] } else { 0 };
dp[i] = skip.max(take);
}
dp[n-1]
}
}
TypeScript
class Solution {
maximumTotalDamage(power: number[]): number {
const freq = new Map<number, number>();
for (const x of power) freq.set(x, (freq.get(x) ?? 0) + 1);
const vals = Array.from(freq.keys()).sort((a, b) => a - b);
const n = vals.length;
const dp = Array(n).fill(0);
for (let i = 0; i < n; ++i) {
const dmg = vals[i] * freq.get(vals[i])!;
let j = i - 1;
while (j >= 0 && vals[j] >= vals[i] - 2) --j;
const skip = i > 0 ? dp[i-1] : 0;
const take = dmg + (j >= 0 ? dp[j] : 0);
dp[i] = Math.max(skip, take);
}
return dp[n-1];
}
}