• [Leetcode]689.Maximum Sum of 3 Non-Overlapping Subarrays


    链接:LeetCode689

    给定数组 nums 由正整数组成,找到三个互不重叠的子数组的最大和。

    每个子数组的长度为k,我们要使这3*k个项的和最大化。

    返回每个区间起始索引的列表(索引从 0 开始)。如果有多个结果,返回字典序最小的一个。

    示例:

    输入: ([1,2,1,2,6,7,5,1], 2)
    输出: ([0, 3, 5])
    解释: 子数组 ([1, 2], [2, 6], [7, 5]) 对应的起始索引为 ([0, 3, 5])
    我们也可以取 ([2, 1]), 但是结果 ([1, 3, 5]) 在字典序上更大。

    相关标签:动态规划

    又是一道明确是用动态规划解法后,便不难想出动态转移方程的题目。
    下面考虑一般情况,也就是求解划分成(N)个不重叠数组的最大和。
    假设到第(i)个元素为止,一共已经产生了(j)个不重叠数组,那么令$ dp[i][j] (表示这)j(个不重叠数组的最大和。 然后就要寻找状态转移方程。**对于第)i$个元素,分为两种情况,可取可不取。**
    如果取,那就说明 (nums[i]) 是第(j)个子数组的最后一个元素,那么转移方程为:

    [dp[i][j] = dp[i-k][j-1]+nums_{i-k+1:i} ]

    也就是说,从(i-k+1)(i),这(k)个元素构成了第(j)个子数组,那我们只需要求到第(i-k)个元素为止,产生(j-1)个不重叠数组的最大和即可。
    如果不取,那问题就变成了求到第(i-1)个元素为止,产生(j)个不重叠数组的最大和,那么转移方程为:

    [dp[i][j] = dp[i-1][j] ]

    当然这题的难度还在于,需要你还原出最大和的情况下,所有子数组的起始元素下标,所以需要另外用一个数组保存一下每一步的最优下标。
    同样,假设到第(i)个元素为止,一共已经产生了(j)个不重叠数组,用(path[i][j])表示第(j)个子数组的末尾元素下标。
    那么按照上面的推断,如果取第(i)个元素,那么(path[i][j]=i);否则的话 (path[i][j]=path[i-1][j])。最后就是根据 path 数组还原答案了。

    其代码如下:

    python:

    class Solution:
        def maxSumOfThreeSubarrays(self, nums: List[int], k: int) -> List[int]:
            n = len(nums)
            dp = [[0 for j in range(4)] for i in range(n+1)]
            path = [[0 for j in range(4)] for i in range(n+1)]
            cur = sum(nums[:k])
            sums = [cur]
            for i in range(k,n):
                cur += nums[i] - nums[i-k]
                sums.append(cur)
    
            for i in range(1,n+1):
                for j in range(1,4):
                    if i < j*k:
                        dp[i][j] = 0
                        continue
                    dp[i][j] = dp[i-1][j]
                    path[i][j] = path[i-1][j]
                    if dp[i-k][j-1] + sums[i-k] > dp[i][j]:
                        dp[i][j] = dp[i-k][j-1] + sums[i-k]
                        path[i][j] = i-k
    
            res = []
            ind = n
            for j in reversed(range(1,4)):
                res.append(path[ind][j])
                ind = path[ind][j]
            res.reverse()
            return res
    

    C++:

    class Solution {
    public:
        vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
            int n = nums.size();
            vector<vector<int>> dp(n+1,vector<int>(4,0));
            vector<vector<int>> path(n+1,vector<int>(4,0));
            int cur = accumulate(nums.begin(),nums.begin()+k,0);
            vector<int> sums{cur};
            for(int i=k;i<n;++i){
                cur += nums[i]-nums[i-k];
                sums.push_back(cur);
            }
            for(int i=1;i<n+1;++i){
                for(int j=1;j<4;++j){
                    if(i<j*k){
                        continue;
                    }
                    dp[i][j] = dp[i-1][j];
                    path[i][j] = path[i-1][j];
                    if(dp[i-k][j-1]+sums[i-k]>dp[i][j]){
                        dp[i][j] = dp[i-k][j-1]+sums[i-k];
                        path[i][j] = i-k;
                    }
                }
            }
            vector<int> res;
            int ind = n;
            for (int j=3;j>0;--j){
                res.insert(res.begin(),path[ind][j]);
                ind = path[ind][j];
            }
            return res;
        }
    };
    

    参考:[LeetCode 689]三个无重叠子数组的最大和

  • 相关阅读:
    fullCalendar改造计划之带农历节气节假日的万年历(转)
    Linked List Cycle
    Remove Nth Node From End of List
    Binary Tree Inorder Traversal
    Unique Binary Search Trees
    Binary Tree Level Order Traversal
    Binary Tree Level Order Traversal II
    Plus One
    Remove Duplicates from Sorted List
    Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/hellojamest/p/12273782.html
Copyright © 2020-2023  润新知