【Lintcode】621. Maximum Subarray V

题目地址:

https://www.lintcode.com/problem/621/

给定一个长 n n n的数组 A A A,再给定两个正整数 k 1 ≤ k 2 k_1\le k_2 k1k2,求所有长度在 [ k 1 , k 2 ] [k_1,k_2] [k1,k2]的子数组中和最大的那个,返回最大子数组和。

先求前缀和数组 p p p,那么对于任意 i i i,实际上就是要求 p [ i − k 2 : i − k 1 ] p[i-k_2:i-k_1] p[ik2:ik1]中的最小值,这可以看成是定长滑动窗口求最值问题,可以用单调队列来做。开一个单调上升队列(存下标,单调性是针对数值的),对于某个 i i i,先将小于 i − k 2 i-k_2 ik2的下标弹出,由于要求最小值,所以将大于等于 p [ i − k 1 ] p[i-k_1] p[ik1]的队尾下标也弹出,最后将 i − k 1 i-k_1 ik1入队尾,那么此时队头存的就是 [ i − k 2 , i − k 1 ] [i-k_2,i-k_1] [ik2,ik1]的最小值。代码如下:

import java.util.ArrayDeque;
import java.util.Deque;

public class Solution {
    /**
     * @param nums: an array of integers
     * @param k1:   An integer
     * @param k2:   An integer
     * @return: the largest sum
     */
    public int maxSubarray5(int[] nums, int k1, int k2) {
        // write your code here
        int n = nums.length;
        if (n < k1) {
            return 0;
        }
        
        Deque<Integer> dq = new ArrayDeque<>();
        int[] preSum = new int[n + 1];
        for (int i = 0; i < n; i++) {
            preSum[i + 1] = preSum[i] + nums[i];
        }
        
        int res = Integer.MIN_VALUE;
        for (int i = k1; i <= n; i++) {
            if (!dq.isEmpty() && i - dq.peekFirst() > k2) {
                dq.pollFirst();
            }
            
            while (!dq.isEmpty() && preSum[dq.peekLast()] >= preSum[i - k1]) {
                dq.pollLast();
            }
            dq.offerLast(i - k1);
            
            // 队头存的就是最小值。
            res = Math.max(res, preSum[i] - preSum[dq.peekFirst()]);
        }
        
        return res;
    }
}

时间复杂度 O ( n ) O(n) O(n),空间 O ( k 2 ) O(k_2) O(k2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值