• 813. 最大平均值和的分组


    813. 最大平均值和的分组

    难度中等283

    给定数组 nums 和一个整数 k 。我们将给定的数组 nums 分成 最多 k 个相邻的非空子数组 。 分数 由每个子数组内的平均值的总和构成。

    注意我们必须使用 nums 数组中的每一个数进行分组,并且分数不一定需要是整数。

    返回我们所能得到的最大 分数 是多少。答案误差在 10-6 内被视为是正确的。

    示例 1:

    输入: nums = [9,1,2,3,9], k = 3
    输出: 20.00000
    解释: 
    nums 的最优分组是[9], [1, 2, 3], [9]. 得到的分数是 9 + (1 + 2 + 3) / 3 + 9 = 20. 
    我们也可以把 nums 分成[9, 1], [2], [3, 9]. 
    这样的分组得到的分数为 5 + 2 + 6 = 13, 但不是最大值.
    

    示例 2:

    输入: nums = [1,2,3,4,5,6,7], k = 4
    输出: 20.50000
    

    提示:

    • 1 <= nums.length <= 100
    • 1 <= nums[i] <= 10^4
    • 1 <= k <= nums.length

    思路:熟悉区间DP的同学应该对这题很熟悉,我们约定dp[i][j][k]表示区间[i,j]划分成k部分能够得到的最大平均值和,那么对于一个区间[L,R],要求它划分成num部分的最大平均值和,首先我们知道num个部分可以看成num-1个部分加上1个部分,因此我们需要枚举分割点M,得到两部分区间[L,M],[M+1,R],这两部分有一个划分成num-1部分,有一个仅仅划分成1部分,存在两种情况,dp[L][M][num-1] + dp[M+1][R][1] 和 dp[L][M][1] + dp[M+1][R][num-1],因此状态转移方程可按照如下表示:

    dp[L][R][num]= \left\{\begin{matrix} \sum_{i=L}^{R}nums[i],num=1 \\ max(dp[L][R][num-1]+dp[M+1][R][1], dp[L][R][1]+dp[M+1][R][num-1]),num>=2,L<=M<R,num<=R-L+1 \\ 0,num>R-L+1 \end{matrix}\right.

    1. class Solution {
    2. public:
    3. double largestSumOfAverages(vector<int>& nums, int k) {
    4. //区间dp
    5. int L, R, n = nums.size(), M, num;
    6. for(int idx = 1; idx < n; ++ idx){
    7. nums[idx] += nums[idx - 1];
    8. }
    9. double dp[101][101][101]{0}, max_value = 0;
    10. for(num = 1; num <= k; ++ num){
    11. for(L = 0; L < n; ++ L){
    12. for(R = L; R < n; ++ R){
    13. if(num == 1){
    14. dp[L][R][1] = (nums[R] - (L == 0 ? 0 : nums[L - 1])) / 1.0 / (R - L + 1);
    15. }else if(R - L + 1 >= num){
    16. //枚举分割点
    17. for(M = L; M < R; ++ M){
    18. dp[L][R][num] = max(dp[L][R][num], max(R - M >= num - 1 ? dp[L][M][1] + dp[M + 1][R][num - 1] : 0, M - L + 1 >= num - 1 ? dp[L][M][num - 1] + dp[M + 1][R][1] : 0));
    19. }
    20. }
    21. }
    22. }
    23. max_value = max(max_value, dp[0][n - 1][num]);
    24. }
    25. return max_value;
    26. }
    27. };

    优化:

            1.本题如果按照上面所述考虑任意的[L,R],那么会需要枚举L,造成状态的大量计算,能不能减少点?其实是可以的,我们一步一步分析。首先本题要求的是nums数组最多划分成k个部分,求最大平均值和,那么其实还是区间合并的问题,不过我们想要略去L的枚举,我们使用dp[y][t]表示[0,x]区间划分为t部分的最大平均值和,那么对于一个x>y,存在转移方程

    dp[x][t+1]=max{dp[y][t]+Avg(y+1,x)}

    即可以理解为,是在原区间[0,y]划分为t部分的基础上,增加一个[y+1,x]的区间得到[0,x]区间上划分为t+1个部分的结果。

            2.能够得到最大平均和的一定是划分为k个部分,证明:不妨设合并前两个部分的区间为[i,h],[h+1,j],合并后变为[i,j],合并前这部分对答案的贡献为

    A \\ =Avg_{i,h}+Avg_{h+1,j} \\=\frac{\sum_{p=i}^{h}nums[p]}{h-i+1}+\frac{\sum_{p=h+1}^{j}nums[p]}{j-h} \\=\frac{(j-i+1)\sum_{p=i}^{h}nums[p]}{(h-i+1)(j-i+1)}+\frac{(j-i+1)\sum_{p=h+1}^{j}nums[p]}{(j-h)(j-i+1)}

    合并后这部分对答案的贡献为

    B \\=Avg_{i,j} \\=\frac{\sum_{p=i}^{j}nums[p]}{j-i+1}

    为了比较这两部分的大小,我们不妨做个除法

    A/B \\=\frac{(j-i+1)\sum_{p=i}^{h}nums[p]}{(h-i+1)\sum_{p=i}^{j}nums[p]}+\frac{(j-i+1)\sum_{p=h+1}^{j}nums[p]}{(j-h)\sum_{p=i}^{j}nums[p]} \\=\frac{Avg_{i,h}}{Avg_{i,j}}+\frac{Avg_{h+1,j}}{Avg_{i,j}} \\=\frac{Avg_{i,h}+Avg_{h+1,j}}{Avg_{i,j}} \\=\frac{(j-i+1)Avg_{i,h}+(j-i+1)Avg_{h+1,j}}{(j-i+1)Avg_{i,j}} \\=\frac{(h-i+1+j-h)Avg_{i,h}+(j-h+h-i+1)Avg_{h+1,j}}{\sum_{p=i}^{j}nums[p]} \\=\frac{\sum_{p=i}^{h}nums[p]+(j-h)Avg_{i,h}+\sum_{p=h+1}^{j}nums[p]+(h-i+1)Avg_{h+1,j}}{\sum_{p=i}^{j}nums[p]} \\=\frac{\sum_{p=i}^{j}nums[p]+(j-h)Avg_{i,h}+(h-i+1)Avg_{h+1,j}}{\sum_{p=i}^{j}nums[p]} \\=1+\frac{(j-h)Avg_{i,h}+(h-i+1)Avg_{h+1,j}}{\sum_{p=i}^{j}nums[p]}>=1

     我们发现,拆分成两部分之后,得到的答案不可能会比原方式要小(仅当所有情况下的子数组的和都为0的情况下),然而本题中说明了1<=nums[i]<=10^4,因此拆分后答案肯定更大。

    1. class Solution {
    2. public:
    3. double largestSumOfAverages(vector<int>& nums, int k) {
    4. //区间dp
    5. int x, y, n = nums.size(), M, num;
    6. for(int idx = 1; idx < n; ++ idx){
    7. nums[idx] += nums[idx - 1];
    8. }
    9. double dp[101][101]{0}, max_value = 0;
    10. for(num = 1; num <= k; ++ num){
    11. for(x = 0; x < n; ++ x){
    12. if(num == 1){
    13. dp[x][1] = nums[x] * 1.0 / (x + 1);
    14. }else{
    15. for(y = max(0, num - 2); y < x; ++ y){
    16. dp[x][num] = max(dp[x][num], dp[y][num - 1] + (nums[x] - nums[y]) * 1.0 / (x - y));
    17. }
    18. }
    19. }
    20. }
    21. return dp[n-1][k];
    22. }
    23. };

  • 相关阅读:
    有望引领下轮牛市的5大加密主题
    一起Talk Android吧(第三百六十六回:多线程之LOCK锁)
    数学建模算法与应用 插值与拟合
    postgres数据库报错无法写入文件 “base/pgsql_tmp/pgsql_tmp215574.97“: 设备上没有空间
    SpringMVC之JSON数据返回与异常处理机制---全方面讲解
    供应原厂电流继电器 - HBDLX-21/3 整定电流范围0.1-1.09A AC220V
    Python requests 模块
    记一次神奇的 pipe 错误
    4 H3C网络设备模拟器
    构建快速、安全、可扩展的静态站点:终极指南
  • 原文地址:https://blog.csdn.net/qq_39304630/article/details/128078799