lintcode 621. 最大子序列

同样出自lintcode

给定一个整数数组,找到长度在 k1 与 k2 之间(包括 k1, k2)的子序列并且使它们的和最大,返回这个最大值,如果数组元素个数小于 k1 则返回 0

Yes

样例

给定一个数组 [-2,2,-3,4,-1,2,1,-5,3],k1 = 2,k2 = 4,连续子序列为 [4,-1,2,1] 时有最大和 6

 

我的解答思路

       如果是一个固定大小的长度子序列k1,那么比较简单,就是k1大小的固定窗口一直滑动求和,将和的最大值给出就行,所以将问题分解为k2-k1+1个固定大小子序列和值的最大值


    public int maxSubarray52(int[] nums, int k1, int k2) {
        // write your code here
        int max = -2147483648;
        int maxLen = k2;
        if(nums.length < k2) maxLen=nums.length;

        //总共需要求maxlen+1-k1个和值
        int[] current = new int[maxLen+1-k1];
        //先求出从第一个元素开始计算的和值
        for(int i=0;i<k1;i++){
            current[0]+=nums[i];
        }

        if(current[0] > max) max = current[0];
        for(int i=1;i<maxLen+1-k1;i++){
            current[i] = current[i-1] + nums[k1 + i-1];
            if(current[i] > max) max=current[i];
        }

        //从第二个元素开始往后滑动所有窗口,每个窗口的的和值=改窗口的前一和值-前一次的首元素+本次的尾元素
        for(int i=1;i<nums.length;i++){
            for(int j=0;j<maxLen+1-k1;j++){
                if(i+ k1 + j-1  >= nums.length) break;
                current[j] += nums[i+ k1+j-1]-nums[i-1];
                if(current[j] > max) max = current[j];
            }
        }

        return max;
    }

提交给lintcode测试,结果在88%时运行超时,不知道什么地方还能优化时间复杂度,有高手请赐教(或者这个思路本身无法达到最优时间复杂度?)

 

看了一下别人的思路,果然不一样。。。

    public int maxSubarray5(int[] nums, int k1, int k2) {
        // write your code here
        if (nums.length < k1) {
            return 0;
        }
    
        int max = Integer.MIN_VALUE;
    
        int[] sum = new int[nums.length + 1];
        //队列:用于最小和值的下标队列(保留i-k1~i-k2之间的和值,并将最小和值保留在队首)
        LinkedList<Integer> queue = new LinkedList<>();
    
        for (int i = 1; i <= nums.length; i++) {
            //一直求和,和=前一元素为止的和+尾元素
            sum[i] = sum[i - 1] + nums[i - 1];

            //最大窗口移动时,将队首移除队列
            if (!queue.isEmpty() && i - queue.getFirst() > k2) {
                queue.removeFirst();
            }
            
            if (i >= k1) {
                while (!queue.isEmpty() && sum[queue.getLast()] > sum[i - k1]) {
                    //如果前面的和值大于i-k1下标和值,则将i-k1替换进去,否则直接将i-k1加入队列
                    queue.removeLast();
                }
                queue.add(i - k1);
            }
    
            // [i - k2, i - k1]
            if (!queue.isEmpty()) {
                max = Math.max(max, sum[i] - sum[queue.getFirst()]);
            }
        }
        
        return max;
    }

 

转载于:https://my.oschina.net/yangboxu/blog/1799648

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值