• 动态规划精讲(一)环形子组数的最大和


    918. 环形子数组的最大和

    题目:

    给定一个由整数数组 A 表示的环形数组 C,求 C 的非空子数组的最大可能和。

    在此处,环形数组意味着数组的末端将会与开头相连呈环状。(形式上,当0 <= i < A.length 时 C[i] = A[i],且当 i >= 0 时 C[i+A.length] = C[i])

    此外,子数组最多只能包含固定缓冲区 A 中的每个元素一次。(形式上,对于子数组 C[i], C[i+1], ..., C[j],不存在 i <= k1, k2 <= j 其中 k1 % A.length = k2 % A.length)

    示例 1:

    输入:[1,-2,3,-2]
    输出:3
    解释:从子数组 [3] 得到最大和 3
    示例 2:

    输入:[5,-3,5]
    输出:10
    解释:从子数组 [5,5] 得到最大和 5 + 5 = 10
    示例 3:

    输入:[3,-1,2,-1]
    输出:4
    解释:从子数组 [2,-1,3] 得到最大和 2 + (-1) + 3 = 4
    示例 4:

    输入:[3,-2,2,-3]
    输出:3
    解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3
    示例 5:

    输入:[-2,-3,-1]
    输出:-1
    解释:从子数组 [-1] 得到最大和 -1

    思路:

    Kanade 算法介绍

    Kadane 算法的伪代码如下

    #Kadane's algorithm
    ans = cur = None
    for x in A:
        cur = x + max(cur, 0)
        ans = max(ans, cur)
    return ans

    方法 1:邻接数组

    代码:

    class Solution {
        public:
        int maxSubarraySumCircular(vector<int> nums) {
            int n =nums.size();
            int ans=nums[0],cur = nums[0];
            //先求左单区间子段,这里包括了整个区间的情况,所以后面的双区间子段不能包括整个区间所以是i+2;
            for (int i = 1; i < n; i++)
            {
                cur = nums[i]+max(cur,0);
                ans = max(ans,cur);
            }
            // cout<<"ans ="<<ans<<endl;
            vector<int>rightsums(n);
            rightsums[n-1]=nums[n-1];
            for (int i = n-2; i >=0; i--)
            {
                rightsums[i] = rightsums[i+1]+nums[i];
            }
    
            vector<int> maxright(n);
            maxright[n-1]=nums[n-1];
            for (int i = n-2; i >= 0; i--)
            {
                maxright[i]=max(maxright[i+1],rightsums[i]);
            }
            int leftsum=0;
            //第一次是比较单区间的情况,后面是双区间的比较
            for (int i = 0; i < n-2; i++)
            {
                leftsum+=nums[i];
                ans = max(ans,leftsum+maxright[i+2]);
            }
            return ans;
        }
    };     

    方法 3:Kadane 算法(符号变种)

     代码:

    class Solution {
        public int maxSubarraySumCircular(int[] A) {
            int S = 0;  // S = sum(A)
            for (int x: A)
                S += x;
    
            int ans1 = kadane(A, 0, A.length-1, 1);
            int ans2 = S + kadane(A, 1, A.length-1, -1);
            int ans3 = S + kadane(A, 0, A.length-2, -1);
            return Math.max(ans1, Math.max(ans2, ans3));
        }
    
        public int kadane(int[] A, int i, int j, int sign) {
            // The maximum non-empty subarray for array
            // [sign * A[i], sign * A[i+1], ..., sign * A[j]]
            int ans = Integer.MIN_VALUE;
            int cur = Integer.MIN_VALUE;
            for (int k = i; k <= j; ++k) {
                cur = sign * A[k] + Math.max(cur, 0);
                ans = Math.max(ans, cur);
            }
            return ans;
        }
    }

     

     优化:

    class Solution {
    public:
        int maxSubarraySumCircular(vector<int>& A) {
            int sofarmax = A[0],sofarmin = A[0],sum = A[0],left = A[0],right = A[0];
            for (int i = 1; i < A.size(); ++i) {
                sum += A[i];
                sofarmax = max(A[i],sofarmax + A[i]);
                sofarmin = min(A[i],sofarmin + A[i]);
                right = max(right,sofarmax);
                left = min(left,sofarmin);
            }
            if(right < 0)
                return right;
            return max(right,sum - left);
        }
    };

     

    因上求缘,果上努力~~~~ 作者:每天卷学习,转载请注明原文链接:https://www.cnblogs.com/BlairGrowing/p/13942313.html

  • 相关阅读:
    jenkins for xcode
    时间你懂的,
    插件,
    basic ,token添加
    上火啊,替换字符串,HTML,
    shell
    不可深究啊,
    看着 自己都感觉 恶心的代码,
    Tab切换效果
    jar -- java文档归档工具
  • 原文地址:https://www.cnblogs.com/BlairGrowing/p/13942313.html
Copyright © 2020-2023  润新知