【Lintcode】1833. Pen Box

题目地址:

https://www.lintcode.com/problem/pen-box/description

给定一个长 n n n的正整数数组 A A A,再给定一个正整数 t t t,要求找到两个不重合的子区间,使得各自和都是 t t t,并且总长度最小。如果解不存在则返回 − 1 -1 1

思路是前缀和 + 双指针。先求出前缀和数组 p p p,然后预处理一个数组 l l l使得 l [ i ] l[i] l[i] A [ 0 : i ] A[0:i] A[0:i]内和为 t t t的子数组的最小长度。由于 A A A里都是正数,所以 p p p单调,所以可以用前后双指针来做。预处理完毕之后,只需再从右向左再用前后双指针枚举以 A [ i ] A[i] A[i]开头的最短的和 t t t的子数组,将其长度加上 l [ i − 1 ] l[i-1] l[i1],就得出了以 A [ i ] A[i] A[i]为第二个区间左端点的最短总长度。枚举完第二区间左端点,就得到了全局最优解。代码如下:

public class Solution {
    /**
     * @param boxes:  number of pens for each box
     * @param target: the target number
     * @return: the minimum boxes
     */
    public int minimumBoxes(int[] boxes, int target) {
        // write your code here
        int len = boxes.length;
        int[] lShort = new int[len], preSum = new int[len + 1];
        // 求前缀和
        for (int i = 0; i < boxes.length; i++) {
            preSum[i + 1] = preSum[i] + boxes[i];
        }
        
        // 预处理lShort数组,lShort[i]是A[0 : i]的最短的和为target的子数组长度
        for (int i = 1, j = 0; i <= len; i++) {
            while (preSum[i] - preSum[j] > target) {
                j++;
            }
            
            if (preSum[i] - preSum[j] == target) {
                lShort[i - 1] = i - j;
            } else if (i - 1 > 0) {
                lShort[i - 1] = lShort[i - 2];
            }
        }
        
        int res = len + 1;
        // 再从右向左求以A[i]开头的最短和target的子数组长度,加上lShort[i - 1]做枚举
        for (int i = len - 1, j = len; i >= 1; i--) {
            while (preSum[j] - preSum[i] > target) {
                j--;
            }
            
            // 这里注意要判断一下lShort[i - 1]不是0,因为有可能左区间不存在,只有在存在的情况下才能参与计算
            if (preSum[j] - preSum[i] == target && lShort[i - 1] != 0) {
                res = Math.min(res, lShort[i - 1] + j - i);
            }
        }
        
        return res == len + 1 ? -1 : res;
    }
}

时空复杂度 O ( n ) O(n) O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值