• 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的数组

  • 相关阅读:
    《C# to IL》第一章 IL入门
    multiple users to one ec2 instance setup
    Route53 health check与 Cloudwatch alarm 没法绑定
    rsync aws ec2 pem
    通过jvm 查看死锁
    wait, notify 使用清晰讲解
    for aws associate exam
    docker 容器不能联网
    本地运行aws lambda credential 配置 (missing credential config error)
    Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?
  • 原文地址:https://www.cnblogs.com/Howfars/p/14745270.html
Copyright © 2020-2023  润新知