leetcode 1031. Maximum Sum of Two Non-Overlapping Subarrays 解法 python

一.问题描述

Given an array A of non-negative integers, return the maximum sum of elements in two non-overlapping (contiguous) subarrays, which have lengths L and M.  (For clarification, the L-length subarray could occur before or after the M-length subarray.)

Formally, return the largest V for which V = (A[i] + A[i+1] + ... + A[i+L-1]) + (A[j] + A[j+1] + ... + A[j+M-1]) and either:

  • 0 <= i < i + L - 1 < j < j + M - 1 < A.lengthor
  • 0 <= j < j + M - 1 < i < i + L - 1 < A.length.

 

Example 1:

Input: A = [0,6,5,2,2,5,1,9,4], L = 1, M = 2
Output: 20
Explanation: One choice of subarrays is [9] with length 1, and [6,5] with length 2.

Example 2:

Input: A = [3,8,1,3,2,1,8,9,0], L = 3, M = 2
Output: 29
Explanation: One choice of subarrays is [3,8,1] with length 3, and [8,9] with length 2.

Example 3:

Input: A = [2,1,5,6,0,9,5,0,3,8], L = 4, M = 3
Output: 31
Explanation: One choice of subarrays is [5,6,0,9] with length 4, and [3,8] with length 3.

 

Note:

  1. L >= 1
  2. M >= 1
  3. L + M <= A.length <= 1000
  4. 0 <= A[i] <= 1000

二.解题思路

首先最简单的就是穷举,可以用回溯,不过感觉这题比较简单没必要用回溯

就是先计算从i到len(A)-L+1个数的之间所有可能的L个数想加的和

然后再计算之后可选的范围内的数的相加,之后两者相加

穷举最重要的就是剪枝操作,否则我觉得会超时,事实也确实如此

如果我们每次都是把从A[i]到A[i+L-1]之间的i个数想加,只能过到42个cases

我们注意到其实每次只要把之前求的sum减去A[i-1]然后加上A[i+L-1]之后的和与上面那行的算法结果是一样的

不过计算量大大减少

同时要注意边界

因为如果头尾两边不够M长度的话,是要跳过的,这时候剪枝要注意,i并不是连贯,所以剪枝所用的更新公式得放在continue语句前面,保证sumL是对的,当然你也可以用一个变量来跟踪

总结难点:

1.边界处理

2.剪枝操作

之后如果有更高效的方法我会更新

更多leetcode算法题解法请关注我的专栏leetcode算法从零到结束或关注我

欢迎大家一起套路一起刷题一起ac

更新:

在discuss里面看到一个O(n)的实现

核心思路是:首先对输入做一个处理,A[i]=A[i]+A[i-1],这样子A[j]-A[i]就是从i到j-1个数的和,不用再做加法

之后更新还是减去头加上尾,和我之前的差不多,不过for循环去掉不少更简洁

for循环去掉的方法是,首先定住一个sumM或者sumL最大值,然后迭代,每次框住L+M个元素,计算sumL和sumM,一边遍历一遍更新res,附java实现java实现,解释得很笼统,最好看源码

三.源码

class Solution:
    def maxSumTwoNoOverlap(self, A: List[int], L: int, M: int) -> int:
        if L<M:
            tmp=L;L=M;M=tmp;
        max_num=0
        sumM=0
        sumL=0;
        for i in range(0,len(A)-L+1):
            if i==0:
                for t in range(i,i+L):
                    sumL+=A[t]
            else:
                # we should pay attention to this step
                # prunning is important,otherwise you will meet TLS
                # if you just simply add from A[i] to A[i+l-1], you will meet TLS
                sumL=sumL-A[i-1]+A[i+L-1]
            if i-1<M and i+L-1+M>len(A)-1:
                continue
            if i-1>=M:
                sumM=0
                for k in range(0,i-M+1):
                    if k==0:
                        for m in range(k,k+M):
                            sumM+=A[m]
                    else:
                        # this is the same as the prunning before
                        sumM=sumM-A[k-1]+A[k+M-1]
                    if sumM+sumL>max_num:
                        max_num=sumM+sumL
            if i+L-1+M<=len(A)-1: 
                sumM=0
                for k in range(i+L,len(A)-M+1):
                    if k==i+L:
                        for m in range(k,k+M):
                            sumM+=A[m]
                    else:
                        # this is the same as the prunning before
                        sumM=sumM-A[k-1]+A[k+M-1]
                    if sumM+sumL>max_num:
                        max_num=sumM+sumL
        return max_num
                    
                    

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值