689. Maximum Sum of 3 Non-Overlapping Subarrays

来源:互联网 发布:win7回收站恢复数据 编辑:程序博客网 时间:2024/06/05 20:11

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], 2Output: [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.

这题最简单粗暴的做法就是,将所有连续的k个数的和存起来之后,三个指针,在相隔k的合法距离内枚举,找到和最大的时候。至于和相同的时候取下标较小的组合,并不需要多余操作,当遍历从0开始的时候,只更新和更大的时候,自然最后得到的下标就是最先出现的最大值。
毫无疑问,暴力解法会超时。
代码:

vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {    int klen = nums.size() - k + 1;    vector<int> ksum(klen, 0);    int i, j, m;    for (i = 0; i < klen; i++) {        for (j = 0; j < k; j++) {            ksum[i] += nums[i + j];        }    }    int max = INT_MIN;    vector<int> ans(3, 0);    for (i = 0; i < klen; i++) {        for (j = i + k; j < klen; j++) {            for (m = j + k; m < klen; m++) {                if (ksum[i] + ksum[j] + ksum[m] > max) {                    ans[0] = i;                    ans[1] = j;                    ans[2] = m;                    max = ksum[i] + ksum[j] + ksum[m];                }            }        }    }    return ans;}

反思这个过程,当i,j固定的时候,我们移动m去寻找剩下序列里的最大值,当j移动一位,又要移动m去找一次最大值,而这种重复非常没有必要,dynamic programming的存在就是为了把同样的索引信息存起来,减少大量的重复劳动。这里我们可以这么考虑,当j固定的时候,i,m的合法范围就是[0, j - k] 和[j + k, klen]. 而我们此时的最大值就是这两个区间里ksum[i]和ksum[m]的最大值。所以我们可以从左往右和从右往左分别建立一个最大值下标的table,每次在一个范围内查找最大值的时候查表就可以了。
代码:

vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {    int klen = nums.size() - k + 1;    vector<int> ksum(klen, 0);    int i, j, m;    for (i = 0; i < klen; i++) {        for (j = 0; j < k; j++) {            ksum[i] += nums[i + j];        }    }    vector<int> left(klen, 0);    vector<int> right(klen, 0);    int maxleft = 0;    int maxright = klen - 1;    for (i = 0; i < klen; i++) {        if (ksum[i] > ksum[maxleft]) {            maxleft = i;        }        left[i] = maxleft;    }    for (m = klen - 1; m >= 0; m--) {        if (ksum[m] >= ksum[maxright]) {            maxright = m;        }        right[m] = maxright;    }    int max = INT_MIN;    vector<int> ans(3, 0);    for (j = k; j <= klen - 1 - k; j++) {        int i = left[j - k];        int m = right[j + k];        int temp_max = ksum[i] + ksum[j] + ksum[m];        if (temp_max > max) {            max = temp_max;            ans[0] = i;            ans[1] = j;            ans[2] = m;        }    }    return ans;}

但这个代码运行时间特别慢。问题出现第一次建立所有长度k的子序列和的时候。上述code里我们建立ksum array的时候,复杂度为O(kN), 当k大的时候,耗时非常大。完全可以用sliding window的想法,降到复杂度O(N).
代码:

int sum = 0;for (i = 0; i < nums.size(); i++) {    sum += nums[i];    if (i >= k) sum -= nums[i - k];    if (i >= k - 1) ksum[i - k + 1] = sum;}
原创粉丝点击