zoukankan      html  css  js  c++  java
  • LeetCode Notes_#1031_两个非重叠子数组的最大和

    LeetCode Notes_#1031_两个非重叠子数组的最大和

    Contents

    题目


    解答

    方法1:暴力搜索

    class Solution {
        public int maxSumTwoNoOverlap(int[] A, int L, int M) {//[0,6,5,2,2,5,1,9,4], L = 1, M = 2
            int[] pre_sum = new int[A.length];
            pre_sum[0] = A[0];
            for(int i = 1; i < A.length; i++){
                pre_sum[i] = pre_sum[i - 1] + A[i];//[0,6,11,13,15,20,21,30,34]
            }
            int max_sum = 0;
            //对于每个[i...i+L-1],遍历所有其他的[j...j+M-1]
            for(int i = 0; i <= A.length - L; i++){//i = 0...8
                for(int j = 0; j <= A.length - M; j++){//j = 0...7
                    //判断是否重叠,如果重叠,直接跳过
                    if(isOverlap(i, L, j, M)) continue;//j = 0, 1
                    if(calSubSum(j, M, pre_sum) == -1 || calSubSum(i, L, pre_sum) == -1) continue;
                    int sum = calSubSum(i, L, pre_sum) + calSubSum(j, M, pre_sum);//重置
                    System.out.println(sum + " " + i + " " + j);
                    if(sum > max_sum) max_sum = sum;
                }
            }
            return max_sum;
        }
        //判断是否重叠:可以直接遍历比较,或者通过区间判断
        private boolean isOverlap(int i, int L, int j, int M){
            // for(int m = i; m <= i + L - 1; m++){
            //     if(m >= j && m <= j + M - 1) return true;
            // }
            // return false;
            if(i > j + M - 1 || j > i + L - 1) return false;//上界>另一个的下界,就说明是不重叠的
            return true;
        }
    
        private int calSubSum(int start, int len, int[] pre_sum){
            if(start < 0 || start + len - 1 >= pre_sum.length) return -1;//-1表示非法范围,主函数应该直接跳过这种情况
            if(start == 0) return pre_sum[start + len - 1];//pre[0+1-1] = 0
            else return pre_sum[start + len - 1] - pre_sum[start - 1];
        }
    }

    复杂度分析

    时间复杂度:O(n^2)
    空间复杂度:O(n),前缀和数组

    方法2:动态规划

    参考C++ 动态规划+滑动窗口 O(n)

    思路

    考虑题意: 必然存在一条分界线把 A 拆分成两半,存在两大类情况:

    1. 长度为 L 的连续子数组在左边, 长度为 M 的连续子数组在右边
    2. 或者反过来长度为 M 的连续子数组在左边, 长度为 L 的连续子数组在右边

    引入

    • dp[i][0]: 从 A[0]-A[i] 连续 L 长度子数组最大的元素和
    • dp[i][1]: 从 A[0]-A[i] 连续 M 长度子数组最大的元素和
    • dp[i][2]: 从 A[i]-A[A.size()-1] 连续 L 长度子数组最大的元素和
    • dp[i][3]: 从 A[i]-A[A.size()-1] 连续 M 长度子数组最大的元素和
      某些超出范围的下标, 值设置为 0 (默认值)
      代码中首先用滑动窗口计算了 dp, 然后将 dp 分成两组, 计算两大类情况下的结果,取最大值返回即可

    代码

    class Solution {
        public int maxSumTwoNoOverlap(int[] A, int L, int M) {
            int[][] dp = new int[A.length][4];
            int presum = 0;
            int maxsum;
            //dp[i][0]:A[i]之前的L数组的最大和
            for(int i = 0; i < L; i++) presum += A[i];
            maxsum = presum;
            dp[L - 1][0] = maxsum;
            for(int i = L; i < A.length; i++){
                presum -= A[i - L];
                presum += A[i];
                maxsum = Math.max(presum, maxsum);
                dp[i][0] = maxsum;
            }
            //dp[i][1]:A[i]之前的M数组的最大和
            presum = 0;
            for(int i = 0; i < M; i++) presum += A[i];
            maxsum = presum;
            dp[M - 1][1] = maxsum;
            for(int i = M; i < A.length; i++){
                presum -= A[i - M];
                presum += A[i];
                maxsum = Math.max(presum, maxsum);
                dp[i][1] = maxsum;
            }
            //dp[i][2]:A[i]之后的L数组的最大和
            int sufsum = 0;
            for(int i = A.length - 1; i >= A.length - L; i--) sufsum += A[i];
            maxsum = sufsum;
            dp[A.length - L][2] = maxsum;
            for(int i = A.length - L - 1; i >= 0; i--){
                sufsum -= A[i + L];
                sufsum += A[i];
                maxsum = Math.max(sufsum, maxsum);
                dp[i][2] = maxsum;
            }
             //dp[i][3]:A[i]之后的M数组的最大和
            sufsum = 0;
            for(int i = A.length - 1; i >= A.length - M; i--) sufsum += A[i];
            maxsum = sufsum;
            dp[A.length - M][3] = maxsum;
            for(int i = A.length - M - 1; i >= 0; i--){
                sufsum -= A[i + M];
                sufsum += A[i];
                maxsum = Math.max(sufsum, maxsum);
                dp[i][3] = maxsum;
            }
            //计算最终结果:dp[i-1][0] + dp[i][3]的最大,dp[i-1][1]+dp[i][2]的最大,找二者中最大
            int res = 0;
            for(int i = L; i <= A.length - M; i++){
                res = Math.max(res, dp[i-1][0] + dp[i][3]);
            }
            for(int i = M; i <= A.length - L; i++){
                res = Math.max(res, dp[i - 1][1] + dp[i][2]);
            }
            return res;        
        }
    }

    复杂度分析

    时间复杂度:O(n)
    空间复杂度:O(n),额外用了4个长度为n的数组

  • 相关阅读:
    vue 集成 vis-network 实现网络拓扑图
    三维空间旋转和Three.JS中的实现
    es6常用新属性(详细整理版)
    css的top和left属性不起作用
    网易云音乐歌单生成外链播放器
    Webstorm常用快捷键备忘
    CPU
    中标麒麟neokylin信息查看
    split分割(拆分)文件
    centos7 安装wps
  • 原文地址:https://www.cnblogs.com/Howfars/p/14745270.html
Copyright © 2011-2022 走看看