Leetcode 689.三个无重叠子数组的最大和(滑动窗口法)

题目描述

题目地址
在这里插入图片描述

思路

思路参考leetcode官方题解:

要计算三个无重叠子数组的最大和,我们可以枚举第三个子数组的位置,同时维护前两个无重叠子数组的最大和及其位置。

要计算两个无重叠子数组的最大和,我们可以枚举第二个子数组的位置,同时维护第一个子数组的最大和及其位置。

因此,我们首先来解决单个子数组的最大和问题,然后解决两个无重叠子数组的最大和问题,最后解决三个无重叠子数组的最大和问题。

前言一:单个子数组的最大和

我们用滑动窗口来解决这一问题。

滑动窗口是数组/字符串问题中常用的抽象概念。窗口通常是指在数组/字符串中由开始和结束索引定义的一系列元素的集合,即闭区间 [i,j]。而滑动窗口是指可以将两个边界向某一方向「滑动」的窗口。例如,我们将 [i,j] 向右滑动 1 个元素,它将变为 [i+1,j+1]

sum1为大小为 k 的窗口的元素和,当窗口从[i−k+1,i] 向右滑动 1 个元素后,sum1增加了nums[i+1],减少了nums[i-k+1]。据此我们可以 O(1)地计算出向右滑动 1 个元素后的窗口的元素和。

我们从[0,k−1] 开始,不断地向右滑动窗口,直至窗口右端点到达数组末尾时停止。统计这一过程中的sum1的最大值(记作maxsum1)及其对应位置。

前言二:两个无重叠子数组的最大和

我们使用两个大小为k的滑动窗口。设sum1为第一个滑动窗口的元素和,该滑动窗口从[0,k-1]开始;sum2为第二个滑动窗口的元素和,该滑动窗口从[k,2k-1]开始。
我们同时向右滑动这两个窗口,并维护sum1的最大值maxsum1及其对应位置。每次滑动时,计算当前maxsum1sum2之和。统计这一过程中的maxsum1+sum2的最大值(记作maxsum12)及其对应位置。

滑动窗口法

回到本题,我们使用三个大小为k的滑动窗口。设sum1为第一个滑动窗口的元素和,该滑动窗口从[0,k-1]sum2为第二个滑动窗口的元素和,该滑动窗口从[k,2k-1]sum3为第三个滑动窗口的元素和,该滑动窗口从[2k,3k-1]开始。
我们同时向右滑动这三个窗口,按照前言二的方法并维护maxsum12及其对应位置。每次滑动前,计算当时maxsum12sum3之和。统计这一过程中的maxsum12+sum3的最大值及其对应位置。
对于题目要求的最小字典序,由于我们是从左到右遍历的,并且当且仅当元素和超过最大元素和时才更新,从而保证求出来的下标列表时字典序最小的。

代码实现

Leetcode代码实现

class Solution {
    
    
public:
    vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) 
    {
    
    
        int sum1=0,maxsum1=0,maxsum1Index=0;
        int sum2=0,maxsum12=0,maxsum12Index1=0,maxsum12Index2=0;
        int sum3=0,maxtotal=0;
        vector<int> ans;
        for(int i=2*k;i<nums.size();i++)
        {
    
    
            sum1+=nums[i-2*k];
            sum2+=nums[i-k];
            sum3+=nums[i];
            if(i>=3*k-1)
            {
    
    
                if(sum1>maxsum1)
                {
    
    
                    maxsum1=sum1;
                    maxsum1Index=i-3*k+1;
                }
                if(maxsum1+sum2>maxsum12)
                {
    
    
                    maxsum12=maxsum1+sum2;
                    maxsum12Index1=maxsum1Index;
                    maxsum12Index2=i-2*k+1;
                }
                if(maxsum12+sum3>maxtotal)
                {
    
    
                    maxtotal=maxsum12+sum3;
                    ans={
    
    maxsum12Index1,maxsum12Index2,i-k+1};
                }
                sum1-=nums[i-3*k+1];
                sum2-=nums[i-2*k+1];
                sum3-=nums[i-k+1];

            }
        }
        return ans;
    }
};

完整代码实现(vs2019运行)

#include<iostream>
#include<vector>

using namespace std;
class Solution {
    
    
public:
    vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k)
    {
    
    
        int sum1 = 0, maxsum1 = 0, maxsum1Index = 0;
        int sum2 = 0, maxsum12 = 0, maxsum12Index1 = 0, maxsum12Index2 = 0;
        int sum3 = 0, maxtotal = 0;
        vector<int> ans;
        for (int i = 2 * k; i < nums.size(); i++)
        {
    
    
            sum1 += nums[i - 2 * k];
            sum2 += nums[i - k];
            sum3 += nums[i];
            if (i >= 3 * k - 1)
            {
    
    
                if (sum1 > maxsum1)
                {
    
    
                    maxsum1 = sum1;
                    maxsum1Index = i - 3 * k + 1;
                }
                if (maxsum1 + sum2 > maxsum12)
                {
    
    
                    maxsum12 = maxsum1 + sum2;
                    maxsum12Index1 = maxsum1Index;
                    maxsum12Index2 = i - 2 * k + 1;
                }
                if (maxsum12 + sum3 > maxtotal)
                {
    
    
                    maxtotal = maxsum12 + sum3;
                    ans = {
    
     maxsum12Index1,maxsum12Index2,i - k + 1 };
                }
                sum1 -= nums[i - 3 * k + 1];
                sum2 -= nums[i - 2 * k + 1];
                sum3 -= nums[i - k + 1];

            }
        }
        return ans;
    }
};

int main()
{
    
    
    vector<int> nums  ={
    
     1,3,2,6,5,3,7,8,9,2,0 };
    Solution s;
    vector<int> res;
    res=s.maxSumOfThreeSubarrays(nums, 2);
    for (auto p : res)
    {
    
    
        cout << p << " ";
    }
}

总结

本题最大的收获是对滑动窗口的更深一步了解,不仅仅局限于一个滑动窗口求最大值,更明白了多个滑动窗口联动求最大和的过程。

在代码实现中有三个if判断,依次确定了sum1的最大在sum1最大时 sum1+sum2的最大在sum1+sum2最大时 sum1+sum2+sum3的最大

值得注意的一点是:虽然三个窗口是联动执行的,但是不意味着三个窗口一定是永远相邻的,因为要通过max值的比较来决定下标是否更改。

猜你喜欢

转载自blog.csdn.net/weixin_45847364/article/details/121792113