• 【每日一题】三个无重叠子数组的最大和


    Tag

    【滑动窗口】【数组】【2023-11-19】


    题目来源

    689. 三个无重叠子数组的最大和


    题目解读


    解题思路

    方法一:滑动窗口

    单个子数组的最大和

    我们先来考虑一个长度为 k 的子数组的最大值与取得最大值时的初始位置。可以使用固定长度的滑动窗口来解决本题。

    滑动窗口是数组和字符串等问题中常用的一个概念。利用滑动窗口可以去掉重复的运算,从而降低时间复杂度。滑动窗口的 “滑动” 指的是窗口每次向右移动一个位置,那么该窗口内的就会增加原窗口右侧的元素,并且会减少原窗口左端点的元素。

    我们从数组 [0, k-1] 区间开始,不断地向右滑动窗口,直至窗口右端点到达数组末尾时停止。统计这一过程中长度为 k 的窗口内元素和 sum1 的最大值(记为 maxSum1)及其对应位置。

    实现代码为:

    class Solution {
    public:
        vector<int> maxSumOfOneSubarray(vector<int> &nums, int k) {
            vector<int> ans;
            int sum1 = 0, maxSum1 = 0;
            for (int i = 0; i < nums.size(); ++i) {
                sum1 += nums[i];
                if (i >= k - 1) {
                    if (sum1 > maxSum1) {
                        maxSum1 = sum1;
                        ans = {maxSum1, i - k + 1};
                    }
                    sum1 -= nums[i - k + 1];
                }
            }
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    两个子数组的最大和

    我们可以仿照 单个子数组的最大和 问题的解题方法,使用两个固定长度的滑动窗口来求解 两个子数组的最大和

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

    实现代码为:

    class Solution {
    public:
        vector<int> maxSumOfTwoSubarrays(vector<int> &nums, int k) {
            vector<int> ans;
            int sum1 = 0, maxSum1 = 0, maxSum1Idx = 0;
            int sum2 = 0, maxSum12 = 0;
            for (int i = k; i < nums.size(); ++i) {
                sum1 += nums[i - k];
                sum2 += nums[i];
                if (i >= k * 2 - 1) {
                    if (sum1 > maxSum1) {
                        maxSum1 = sum1;
                        maxSum1Idx = i - k * 2 + 1;
                    }
                    if (maxSum1 + sum2 > maxSum12) {
                        maxSum12 = maxSum1 + sum2;
                        ans = {maxSum1Idx, i - k + 1};
                    }
                    sum1 -= nums[i - k * 2 + 1];
                    sum2 -= nums[i - k + 1];
                }
            }
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    三个子数组的最大和

    在本题中,可以使用三个长度为 k 的滑动窗口。设 sum1 为第一个滑动窗口的元素和,该滑动窗口从 [0, k - 1] 开始,sum2 为第二个滑动窗口的元素和,该滑动窗口从 [k, 2*k - 1] 开始,sum3 为第三个滑动窗口的元素和,该滑动窗口从 [2*k, 3*k - 1] 开始。

    我们同时向右滑动这三个窗口,并维护 maxSum12 及其对应位置。每次滑动时,记录当前的 maxSum12sum3 之和。统计这一过程中的 maxSum12 + sum3 的最大值(记作 maxTotal)及其对应位置。

    对于题目要求的最小字典序,由于我们是从左向右遍历的,并且仅当元素和超过最大元素和时才修改最大元素和,从而保证求出来的下标列表是字典序最小的。

    复杂度分析

    class Solution {
    public:
        vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
            vector<int> res;
            int sum1 = 0, maxSum1 = 0, maxSum1Idx = 0;
            int sum2 = 0, maxSum12 = 0, maxSum12Idx1 = 0, maxSum12Idx2 = 0;
            int sum3 = 0, maxTotal = 0;
            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;
                        maxSum1Idx = i - 3 * k + 1; 
                    }
                    if (maxSum1 + sum2 > maxSum12) {
                        maxSum12 = maxSum1 + sum2;
                        maxSum12Idx1 = maxSum1Idx;
                        maxSum12Idx2 = i - 2 * k + 1;
                    }
                    if (maxSum12 + sum3 > maxTotal) {
                        maxTotal = maxSum12 + sum3;
                        res = {maxSum12Idx1, maxSum12Idx2, i - k + 1};
                    }
                    sum1 -= nums[i - 3 * k + 1];
                    sum2 -= nums[i - 2 * k + 1];
                    sum3 -= nums[i -  k + 1];
                }
            }
            return res;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    复杂度分析

    时间复杂度: O ( n ) O(n) O(n)

    空间复杂度: O ( 1 ) O(1) O(1)


    写在最后

    如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

    如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

    最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

  • 相关阅读:
    CSS的break-inside 属性 的使用
    可变参数模板
    二、搭建Java环境
    目录遍历漏洞
    【STM32训练—WiFi模块】第一篇、STM32驱动ESP8266WiFi模块获取网络时间
    Day07--wxs的概念以及其基本的用法
    未来展望:Starday供应链火力全开,为跨境电商再添动力!
    精彩回顾 l Rust唠嗑室:Xline跨数据中心一致性管理
    uniapp微信小程序使用xr加载模型
    人人开源前后端分离开源项目启动流程(超详细)
  • 原文地址:https://blog.csdn.net/weixin_54383080/article/details/134497807