LeetCode·每日一题·813.最大平均值和的分组·动态规划

作者:小迅
链接:https://leetcode.cn/problems/largest-sum-of-averages/solutions/1995361/dong-tai-gui-hua-zhu-shi-chao-ji-xiang-x-x9wc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 

题目

 

思路

平均值和最大的分组的子数组数目必定是 k --> 因为数组元素大于 1 那么任意一个子数组的平均值肯定 >= 1,那么累加肯定会增大

为了方便计算子数组的平均值,我们使用一个数组 sum 来保存数组 nums 的前缀和。其中 dp[i][j] 的含义 表示 nums 在区间 [0,i−1] 被切分成 j 个子数组的最大平均值和,显然 i≥j,计算分两种情况讨论:

当 j=1 时,dp[i][j] 是对应区间 [0, i - 1] 的平均值;
当 j>1 时,我们可以将区间 [0, i - 1] 分成 [0, x - 1] 和 [x, i - 1] 两个部分,其中 x≥j−1,并且不唯一
那么 dp[i][j] 等于所有这些合法的切分方式的平均值和的最大值。即转移表达式为 :dp[i][j] = MAX(dp[i][j], dp[x][j - 1] + (sum[i] - sum[x]) / (i - x)),其中 dp[x][j - 1] + (sum[i] - sum[x]) / (i - x) 表示为 x 位置 之前的最大值分组和 + 当前位置平均值

代码


#define MAX(a, b) ((a) > (b) ? (a) :(b))

double largestSumOfAverages(int* nums, int numsSize, int k){
    double sum[numsSize + 1];
    sum[0] = 0.0;
    for (int i = 0; i < numsSize; ++i) {//前缀和
        sum[i+1] = sum[i] + nums[i];
    }
    double dp[numsSize + 1][k + 1];
    for (int i = 1; i <= numsSize; ++i) {//最佳分组
        dp[i][1] = sum[i] / i;
    }
    for (int j = 2; j <= k; ++j) {//枚举分组数
        for (int i = j; i <= numsSize; ++i) {//枚举数组元素
            dp[i][j] = 0.0;
            for (int x = j - 1; x < i; ++x) {//枚举分割位置
                dp[i][j] = MAX(dp[i][j], dp[x][j - 1] + (sum[i] - sum[x]) / (i - x));//取最佳分组位置和
            }
        }
    }
    return dp[numsSize][k];
}

作者:小迅
链接:https://leetcode.cn/problems/largest-sum-of-averages/solutions/1995361/dong-tai-gui-hua-zhu-shi-chao-ji-xiang-x-x9wc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值