【每日一题Day182】LC1043分隔数组以得到最大和 | dp

该文介绍了如何使用动态规划解决LeetCode第1043题,目标是将一个整数数组按照最多k个连续子数组进行分割,每个子数组内的数值变为该子数组的最大值,从而求出元素的最大和。动态规划策略是通过枚举分割点并计算不同分割方式下的最大和,状态转移方程为dp[i+1]=max(dp[j]+mx*(i-j+1)),其中mx是子数组nums[j:i]的最大值。时间复杂度为O(nk),空间复杂度为O(n)。

分隔数组以得到最大和【LC1043】

给你一个整数数组 arr,请你将该数组分隔为长度 最多 为 k 的一些(连续)子数组。分隔完成后,每个子数组的中的所有值都会变为该子数组中的最大值。

返回将数组分隔变换后能够得到的元素最大和。本题所用到的测试用例会确保答案是一个 32 位整数。

二十分钟 满足了

  • 思路

    使用动态规划,将前iii个元素进行分割的最大和,可以枚举分割点由之前的状态转移得到,因此可以定义状态dp[i+1]dp[i+1]dp[i+1]为将iii个元素分隔变换后能够得到的元素最大和

    • 明确 dp 函数/数组的定义

      定义状态dp[i+1]dp[i+1]dp[i+1]为将iii个元素分隔变换后能够得到的元素最大和

    • 确定 base case,初始状态的值:dp[0]=0dp[0]=0dp[0]=0

    • 确定「状态」,也就是原问题和子问题中会变化的变量

      本题中状态为分隔变换后能够得到的元素最大和

    • 确定「选择」,也就是导致「状态」产生变化的行为

      iii个元素最长可以分割的子数组为nums[i−k+1:i]nums[i-k+1:i]nums[ik+1:i],因此可以枚举与nums[i]nums[i]nums[i]为一组的左端点j∈[i−k+1,i]j \in [i-k+1,i]j[ik+1,i],此时的最大和为将nums[0:j−1]nums[0:j-1]nums[0:j1]进行分割的最大值与nums[j:i]nums[j:i]nums[j:i]变换后的值之和

      。实现时,使用变量记录当前子数组nums[j:i]nums[j:i]nums[j:i]中元素的最大值mxmxmx,于是可以得到状态转移方程
      dp[i+1]=maxj=ii−k+1(dp[j]+mx∗(i−j+1)) dp[i+1]=max_{j=i}^{i-k+1}(dp[j]+mx*(i-j+1)) dp[i+1]=maxj=iik+1(dp[j]+mx(ij+1))

  • 实现

    class Solution {
        public int maxSumAfterPartitioning(int[] arr, int k) {
            int n = arr.length;
            int[] dp = new int[n + 1];       
            for (int i = 0; i < n; i++){
                int mx = arr[i];
                for (int j = i; j >= Math.max(0, i - k + 1); j--){
                    mx = Math.max(mx, arr[j]);
                    dp[i + 1] = Math.max(dp[i + 1], dp[j] + mx * (i - j + 1));
                }
            }
            return dp[n];
    
        }
    }
    
    • 复杂度

      • 时间复杂度:O(nk)O(nk)O(nk)
      • 空间复杂度:O(n)O(n)O(n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值