LeetCode | 689. Maximum Sum of 3 Non-Overlapping Subarrays 困难DP题分析与解答

本文介绍了一种寻找给定数组中三个不重叠子数组的最大和的方法,并提供了一个高效的算法实现。该算法不仅解决了特定问题,还扩展到了更多组的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Ina given array nums ofpositive integers, find three non-overlapping subarrays with maximum sum.

Eachsubarray will be of size k, and we want to maximize the sum of all 3*k entries.

Returnthe result as a list of indices representing the starting position of eachinterval (0-indexed). If there are multiple answers, return thelexicographically smallest one.

Example:

Input: [1,2,1,2,6,7,5,1], 2

Output: [0, 3, 5]

Explanation: Subarrays [1, 2], [2, 6], [7, 5]correspond to the starting indices [0, 3, 5].

We could have also taken [2, 1], but an answer of [1, 3, 5]would be lexicographically larger.

Note:

· nums.length will be between 1 and 20000.

· nums[i] will be between 1 and 65535.

· k will be between 1 and floor(nums.length / 3).

这题研究了相当久,最后一次就ac了,我也没想到这么复杂的dp一次就能ac,这题当然也有简单的方法,简单的方法就是利用分组的特性,将nums分为left,middle,right三组,

left[i]用来求nums从左到右0~i-1最大的一个分组,

right[i]表示nums从右到左i~n-1最大的分组,

这样middle[i]表示当中间一组取起点为i的变量的时候最大的三组,这样取所有left[i-1]+nums[i]+right[i+1]中最大的一个就能得到最终的结果,时间为O(n),这种方法虽然简单,但是适用性很窄,只适用3组的情况。

接下来的方法适用于m组,每组长度为k的情况,dp[t][i]表示t组,0~i-1范围类t组最大的和,store[t][i]表示0~i-1范围t组最大和方案最后一组选择的index,那么可知theNumSum[i],表示nums中从nums[i]开始累加累加k次之后的值,那么可知 dp[t][i]=max(dp[t-1][i-k]+theNumSum[i-k],dp[t][i-1]),的值,这样不断是用dp,直到dp[m][n](n为nums的长度)得到之后,dp[m][n]就是最大的和,但是得到最大和还不够,还需要最大和方案,这个时候store就派上了用场,按照程序中的方法检索store,就能得到最终的结果,这个算法的时间复杂度为O(mn),m为分组的个数,可知,仍然是线性时间复杂度

class Solution {
public:
vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
	vector<int> dp[2];
	int n = nums.size(); int index;
	int howMany = 3;//howmany表示分组的个数
	dp[0] = vector<int>(n + 1, 0);
	dp[1] = vector<int>(n + 1, 0);
	vector<vector<int>> store(howMany + 1, vector<int>(n + 1, 0));
	vector<int> result;

	vector<int> theSum(n, 0);
	theSum[0] = 0;
	for (int i = 0; i < k; i++)
	{
		theSum[0] += nums[i];
	}
	for (int i = 1; i <= n - 1-k+1; i++)
	{
		theSum[i] = theSum[i - 1] - nums[i - 1] + nums[i + k-1];
	}

	for(int l=1;l<=howMany;l++)
		for (int i = 1 + l*k - 1; i <= n; i++)
		{
			index = (l - 1) % 2;
			int a = dp[index][i - k] + theSum[i - k];
			int b = dp[l % 2][i - 1];
			if (a > b)
			{
				dp[l % 2][i] = a;
				store[l][i] = i - k+1;
			}
			else
			{
				dp[l % 2][i] = b;
				store[l][i] = store[l][i-1];
			}
		}
	index = n;
	for (int i = howMany; i >= 1; i--)
	{
		result.push_back(store[i][index]-1);
		index = store[i][index] - 1;
	}
	n = result.size();
	for (int i = 0; i < result.size() / 2; i++)
	{
		swap(result[i], result[n - 1 - i]);
	}
	return result;
}
};




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值