题目
思路
1.暴力遍历
首先求得位置poi的k项和数组,数组长度为nums的length-k+1
sum_arr[0] = accumulate(nums.begin(), nums.begin() + k, 0);
for (int i = 1; i < sum_arr.size(); ++i)
sum_arr[i] = sum_arr[i - 1] - nums[i - 1] + nums[i + k - 1];
然后进行三层遍历,第n层遍历第n/3个子数组的起始位置,暴力遍历每种情况的的子数组和,最后得到最大的输出。
class Solution {
public:
vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
vector<int> sum_arr(nums.size() - k + 1);
sum_arr[0] = accumulate(nums.begin(), nums.begin() + k, 0);
for (int i = 1; i < sum_arr.size(); ++i)
sum_arr[i] = sum_arr[i - 1] - nums[i - 1] + nums[i + k - 1];
vector<int> result;
int sum = 0;
for (int i = 0; i < sum_arr.size() - k * 2; ++i)
for (int j = i + k; j < sum_arr.size() - k; ++j)
for (int t = j + k; t < sum_arr.size(); ++t)
if (sum < sum_arr[i] + sum_arr[j] + sum_arr[t]) {
sum = sum_arr[i] + sum_arr[j] + sum_arr[t];
result = {
i, j, t};
}
return result;
}
};
2.滑动窗口
思路:
要计算三个无重叠子数组的最大和,我们可以枚举第三个子数组的位置,同时维护前两个无重叠子数组的最大和及其位置。
要计算两个无重叠子数组的最大和,我们可以枚举第二个子数组的位置,同时维护第一个子数组的最大和及其位置。
因此,我们首先来解决单个子数组的最大和问题,然后解决两个无重叠子数组的最大和问题,最后解决三个无重叠子数组的最大和问题。
窗口移动时,当第一个窗口的和变大后,要使用此位置的和,必然需要第二个位置的窗口也使用新窗口,当两者和比原来大时,才能更新两个子数组的开始位置。第三个窗口同理,当前两窗口和+第三窗口和大于原来时,才能更新三个子数组的位置。
class Solution {
public:
vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
int first_sum = 0, second_sum = 0, third_sum = 0;
int first_idx = 0, second_idx = k, second_sum_first_idx = 0;
int first_max = 0, second_max = 0, third_max = 0;
vector<int> result;
for (int i = 2 * k; i < nums.size(); ++i) {
first_sum += nums[i - 2 * k];
second_sum += nums[i - k];
third_sum += nums[i];
if (i >= 3 * k - 1) {
if (first_sum > first_max) {
first_max = first_sum;
first_idx = i - 3 * k + 1;
}
if (first_max + second_sum > second_max) {
second_max = first_max + second_sum;
second_sum_first_idx = first_idx;
second_idx = i - 2 * k + 1;
}
if (second_max + third_sum > third_max) {
result = {
second_sum_first_idx, second_idx , i - k + 1 };
third_max = second_max + third_sum;
}
first_sum -= nums[i - k * 3 + 1];
second_sum -= nums[i - k * 2 + 1];
third_sum -= nums[i - k + 1];
}
}
return result;
}
};
3.动态规划
核心推导:
i代表i+1个子数组,j代表k+j个数字,dp[i][j]代表i+1个子数组、数组长度为k+j时数组和的值。
按照递推关系,进行动态规划求解。
然后对于这个数组,dp[i][j]随着j减小开始变化时,设开始变化的位置为d,则d+1为第i+1个子数组的开始位置,然后对其位置减去k,dp[i-1][d+1-k]随着d+1-k减小开始变化时,此位置为第i个子数组的开始位置,以此类推。
class Solution {
public:
vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
vector<vector<int>> dp(3, vector<int>(nums.size() - k + 1, 0));
vector<int> sum_arr(nums.size() - k + 1);
vector<int> result(3);
sum_arr[0] = accumulate(nums.begin(), nums.begin() + k, 0);
for (int i = 1; i < sum_arr.size(); ++i)
sum_arr[i] = sum_arr[i - 1] - nums[i - 1] + nums[i + k - 1];
int temp = 0;
for (int i = 0; i < 3; ++i) {
for (int j = i * k; j < nums.size() - k + 1; ++j) {
if (i == 0)
temp = sum_arr[j];
else
temp = dp[i - 1][j - k] + sum_arr[j];
if (j == i * k)
dp[i][j] = temp;
else
dp[i][j] = max(dp[i][j - 1], temp);
}
}
int j = nums.size() - k;
for (int i = 2; i >= 0; --i) {
while (j != 0 && dp[i][j] == dp[i][j - 1])
j--;
result[i] = j;
j = j - k;
}
return result;
}
};