如何利用C++、C、Python求最大总和圆形子阵列

129 阅读1分钟

问题

给出一个圆形整数阵 nums 长度为 n的非空子数组的最大可能之和nums.

循环数组意味着数组的终点与数组的起点相连接。从形式上看,数组的下一个元素 nums[i] 的下一个元素是 nums[(i + 1) % n] 的前一个元素是 nums[i]nums[(i - 1 + *n*) % n].

请注意,原数组的一个索引在结果子数组中不能出现两次。

处理方法

最大的子数组可以有两种情况。子数组要么不是圆形的(只是原数组的一个子数),要么是圆形的(将从起点开始绕过)。

在第一种情况下,使用Kadane的程序来获得最大的子阵列之和。

在第二种情况下,可以找到最小的子数组之和,并且可以从原数组的总和中减少。当然,这将使我们得到剩余子阵列的最大和。

基于以上两种情况,返回最大值。

但还有一种情况是余数。如果所有的元素都是负数,则返回其中最大的一个。

C++编程

#include<bits/stdc++.h>
using namespace std;

int maxSubarraySumCircular(vector<int>& nums) {
        int total = accumulate(nums.begin(), nums.end(), 0);
        int n = nums.size();
        vector<int>nums1=nums;
        sort(nums1.begin(), nums1.end());
        
        if(nums1[0]<0 && nums1[n-1]<0){   //if all elements are negative
            return nums1[n-1];
        }
        int sum0 = 0;
        int ans0 = 0;
        for(int i=0; i<n; i++){    //kadane's algorithm for original array
            sum0 += nums[i];
            sum0 = max(sum0,0);
            ans0 = max(ans0,sum0);
        }
        for(int i=0; i<n; i++){       //change sign of each number
            nums[i]*=-1;
        }
        int sum = 0;
        int ans = 0;
        for(int i=0; i<n; i++) //kadane's algorithm after changing signs
        {   
            sum += nums[i];
            sum = max(sum,0);
            ans = max(ans,sum);
        }
        return max(total-(-1*ans), ans0);
    }
int main(){
vector<int>v{1, 2, -1, 77};
cout<<maxSubarraySumCircular(v);
}

输出

80

C语言编程

#include <stdio.h>
int findMaxSubarray(int a[], int n)
{
   int res = 0, sum = 0;
   int i;
   for (i = 0; i < n; i++) {
       sum = sum + a[i];
       if (sum < 0)
           sum = 0;
       if (res < sum)
           res = sum;
   }
   return res;
}

int maxSubarraySum(int a[], int n)
{
   //get the maximum sum using standard findMaxSubarray'
   int ans0 = findMaxSubarray(a, n);

   //find the maximum sum that includes
   // corner elements.
   int ans = 0, i;
   for (i = 0; i < n; i++) {
       ans += a[i]; // Calculate array-sum
       a[i] = -a[i]; // invert the array (change sign)
   }

   // max sum with corner elements will be:
   // array-sum - (-max subarray sum of inverted array)
   ans = ans + findMaxSubarray(a, n);

   return (ans > ans0) ? ans : ans0;
}

int main()
{
   int a[] = {1, 2, -1, 77};
   int n = sizeof(a) / sizeof(a[0]);
   printf("Maximum sum is %d",
       maxSubarraySum(a, n));
}

输出

Maximum sum is 80

Python编程

def maxSubarray(a):
   n = len(a)
   ans = 0
   sum = 0
   for i in range(0, n):
       sum = sum + a[i]
       if (sum < 0):
           sum = 0
       if (ans < sum):
           ans = sum
   return ans

def maxSubarraySumCircular(a):

   n = len(a)

   # get the maximum sum using standard maxSubarray
   ans0 = maxSubarray(a)

   # Now find the maximum sum that includes corner
   # elements.
   ans = 0
   for i in range(0, n):
       ans += a[i]
       a[i] = -a[i]

   # Max sum with corner elements will be:
   # array-sum - (-max subarray sum of inverted array)
   ans = ans + maxSubarray(a)

   if ans > ans0:
       return ans
   else:
       return ans0

a = [1,2,-1,77]
print ("Maximum sum is", maxSubarraySumCircular(a))

输出

Maximum sum is 80