leetcode689. Maximum Sum of 3 Non-Overlapping Subarrays

本文探讨了一种寻找数组中三个不重叠子数组的最大和的问题,并提供了三种不同复杂度的解决方案,从简单暴力搜索到高效的线性时间复杂度算法。

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

In a given array nums of positive integers, find three non-overlapping subarrays with maximum sum.
Each subarray will be of size k, and we want to maximize the sum of all 3*k entries.
Return the result as a list of indices representing the starting position of each interval (0-indexed). If there are multiple answers, return the lexicographically 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).

题目要求从一个数组中取三个不重叠的、长度都为k的子数组,并使取得的三个子数组总和最大。

Solution One

最简单的解法就是用三个循环从头到尾全遍历一遍,时间复杂度为O(n^3),这个解法虽然没错,但很慢,在leetcode上跑回超时

class Solution {
public:
    vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
        int i, j, h, s, tempsum;
        int size = nums.size();
        vector<int> sum;
        for (i = 0; i < size - k + 1; ++i) {
            s = 0;
            for (j = 0; j < k; ++j) {
                s += nums[i + j];
            }
            sum.push_back(s);
        }
        vector<int> answer(3, 0);
        int maxsum = 0;
        for (i = 0; i < size - 3 * k + 1; ++i) {
            for (j = i + k; j < size - 2 * k + 1; ++j) {
                for (h = j + k; h < size - k + 1; ++h) {
                    tempsum = sum[i] + sum[j] + sum[h];
                    if (tempsum > maxsum) {
                        maxsum = tempsum;
                        answer = {i,j,h};
                    }
                }
            }
        }
        return answer;
    }
};
Solution Two

进阶一点就是先固定中间的子数组地址 j,这样整个数组就被分成了左右两边,各取左右两边最大的那个作为另外两个子数组地址 i,h 就可以了,时间复杂度为O(n^2),leetcode运行时间 557 ms

class Solution {
public:
    vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
        int i, j, h, s = 0, tempsum;
        int size = nums.size();
        vector<int> sum;
        for (i = 0; i < size; ++i) {
            s += nums[i];
            if (i >= k)
                s -= nums[i - k];
            if (i >= k - 1)
                sum.push_back(s);
        }
        vector<int> answer(3, 0);
        int maxsum = 0;
        for (j = k; j < size - 2 * k + 1; ++j) {
            int maxi = 0, maxh = 0, maxsumi = 0, maxsumh = 0;
            for (i = 0; i < j - k + 1; ++i) {
                if (sum[i] > maxsumi) {
                    maxi = i;
                    maxsumi = sum[i];
                }
            }
            for (h = j + k; h < size - k + 1; ++h) {
                if (sum[h] > maxsumh) {
                    maxh = h;
                    maxsumh = sum[h];
                }
            }
            tempsum = sum[maxi] + sum[j] + sum[maxh];
            if (tempsum > maxsum) {
                maxsum = tempsum;
                answer = {maxi,j,maxh};
            }
        }
        return answer;
    }
};
Solution Three

更进一步可以提前遍历一遍算好前n个或后n个子数组中的最大值,这样在解法二中 i,h 就可以直接取值而不用每次去求最大值了,时间复杂度为O(n),leetcode运行时间 36 ms

class Solution {
public:
    vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
        int i, j, h, s = 0, tempsum;
        int size = nums.size();
        vector<int> sum;
        for (i = 0; i < size; ++i) {
            s += nums[i];
            if (i >= k)
                s -= nums[i - k];
            if (i >= k - 1)
                sum.push_back(s);
        }
        int best = 0;
        vector<int> left(sum.size(), 0);
        for (i = 0; i < sum.size(); ++i) {
            if (sum[i] > sum[best])
                best = i;
            left[i] = best;
        }
        best = sum.size() - 1;
        vector<int> right(sum.size(), 0);
        for (i = sum.size() - 1; i >= 0; --i) {
            if (sum[i] > sum[best])
                best = i;
            right[i] = best;
        }
        vector<int> answer(3, 0);
        int maxsum = 0;
        for (j = k; j < size - 2 * k + 1; ++j) {
            tempsum = sum[left[j - k]] + sum[j] + sum[right[j + k]];
            if (tempsum > maxsum) {
                maxsum = tempsum;
                answer = {left[j-k],j,right[j+k]};
            }
        }
        return answer;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值