Leetcode每日一练--41

3186. 施咒的最大总伤害

难度:中等

提示

一个魔法师有许多不同的咒语。

给你一个数组 power ,其中每个元素表示一个咒语的伤害值,可能会有多个咒语有相同的伤害值。

已知魔法师使用伤害值为 power[i] 的咒语时,他们就 不能 使用伤害为 power[i] - 2 ,power[i] - 1 ,power[i] + 1 或者 power[i] + 2 的咒语。

每个咒语最多只能被使用 一次 。

请你返回这个魔法师可以达到的伤害值之和的 最大值 。

示例 1:

输入:power = [1,1,3,4]

输出:6

解释:

可以使用咒语 0,1,3,伤害值分别为 1,1,4,总伤害值为 6 。

示例 2:

输入:power = [7,1,6,6]

输出:13

解释:

可以使用咒语 1,2,3,伤害值分别为 1,6,6,总伤害值为 13 。

提示:

  • 1 <= power.length <= 10^5
  • 1 <= power[i] <= 10^9

代码

#include <stdlib.h>
#include <stdio.h>

int compare(const void* a, const void* b) {
    return (*(int*)a - *(int*)b);
}

long long maximumTotalDamage(int* power, int powerSize) {
    if (powerSize == 0) return 0;
    
    // 对原数组排序以便统计
    qsort(power, powerSize, sizeof(int), compare);
    
    // 统计不同伤害值的总伤害
    int* damage = (int*)malloc(powerSize * sizeof(int));
    long long* valueList = (long long*)malloc(powerSize * sizeof(long long));
    int count = 0; // 不同伤害值的数量
    
    for (int i = 0; i < powerSize; i++) {
        if (i == 0 || power[i] != power[i-1]) {
            damage[count] = power[i];
            valueList[count] = power[i];
            count++;
        } else {
            valueList[count-1] += power[i];
        }
    }
    
    if (count == 0) {
        free(damage);
        free(valueList);
        return 0;
    }
    
    // 动态规划数组
    long long* dp = (long long*)malloc(count * sizeof(long long));
    long long* pre = (long long*)malloc(count * sizeof(long long));
    int j = -1; // 指针,指向满足 damage[j] <= damage[i]-3 的最大下标
    
    for (int i = 0; i < count; i++) {
        // 移动指针 j
        while (j + 1 < i && damage[j+1] <= damage[i] - 3) {
            j++;
        }
        
        // 计算 dp[i]
        if (j >= 0) {
            dp[i] = valueList[i] + pre[j];
        } else {
            dp[i] = valueList[i];
        }
        
        // 更新 pre[i]
        if (i == 0) {
            pre[i] = dp[i];
        } else {
            pre[i] = (pre[i-1] > dp[i]) ? pre[i-1] : dp[i];
        }
    }
    
    long long ans = pre[count-1];
    
    // 释放内存
    free(damage);
    free(valueList);
    free(dp);
    free(pre);
    
    return ans;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值