JAVA程序设计:三个无重叠子数组的最大和(LeetCode:689)

给定数组 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] 在字典序上更大。
注意:

nums.length的范围在[1, 20000]之间。
nums[i]的范围在[1, 65535]之间。
k的范围在[1, floor(nums.length / 3)]之间。

思路:我们可以将本题扩展到找到n个互补重叠的子数组的最大和,定义dp[i][j]:表示截止到nums[i]形成的第j个无重叠子数组的最大和,path[i][j]代表截止到nums[i]形成的第j个无重叠子数组以哪个下标为结尾,用来回溯路径。

class Solution {
    public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
        
    	return maxSumOfNSubarrays(nums,k,3);
    	
    }
    
    private int[] maxSumOfNSubarrays(int[] nums,int k,int n) {
    	
    	if(k<1 || k*n>nums.length) return new int[3];
    	
    	int N=nums.length;
    	int s=0;
    	for(int i=0;i<k;i++)
    		s+=nums[i];
    	
    	int[] sums=new int[N];
    	sums[k-1]=s;
    	for(int i=k;i<N;i++) {
    		s+=nums[i]-nums[i-k];
    		sums[i]=s;
    	}
    	
    	int[][] dp=new int[N+1][n+1];
    	int[][] path=new int[N+1][n+1];
    	
    	dp[k-1][1]=sums[k-1];
    	path[k-1][1]=k-1;
    	for(int i=k;i<N;i++)
    		for(int j=1;j<=n;j++) {
    			dp[i][j]=dp[i-1][j];
    			path[i][j]=path[i-1][j];
    			if(sums[i]+dp[i-k][j-1]>dp[i][j]) {
    				dp[i][j]=sums[i]+dp[i-k][j-1];
    				path[i][j]=i;
    			}
    		}
    	
    	int len=0;
    	int[] res=new int [n];
    	int last=path[N-1][n];
    	res[len++]=last-k+1;
    	for(int i=n-1;i>0;i--) {
    		last=path[last-k][i];
    		res[len++]=last-k+1;
    	}
    	
    	Arrays.parallelSort(res);
    	
    	return res;
    }
}
发布了987 篇原创文章 · 获赞 175 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/haut_ykc/article/details/104157187