Divide and conquer: the largest subarray problem
Question:
Given an array, find a sub-array (contiguous) so that the sum of the elements of the sub-array is the largest.
Input:
Given an array X[1...n], for any pair of non-empty sub-arrays with array subscripts l,r(l≤r), the sum is recorded as S(l,s).
Output:
Find S The maximum value of (l, s) is recorded as S max .
problem analysis
- Divide the array X[1…n] into X[1…n/2] and X[n/2 +1…n]
- Recursively solve the sub-problem
S1 : the largest sub-array of the array X[1…n/2]
S2 : the largest sub-array of the array X[n/2+1…n] - Combine the sub-problems to get S max
S3 : the largest sub-array across the midpoint. The
sum of the most princely sub-arrays of the array X S max =max{S1,sz,s3}
The bottleneck value of execution efficiency is in terms of merging, which is the problem of solving S3.
S3 solution:
-
记mid = n/2
-
S3 can be divided into two parts
Left : the sum of the largest sub-array ending with X[mid]
Right : the sum of the largest sub-array starting with X[mid+1]
S3 = Left + RightSolution of Left:
traverse the sum from X[mid] forward and record the maximum value
. Solution of Right:
traverse the sum from X[mid +1] backward and record the maximum value
S3 time complexity:
- Left time complexity: O(mid)
- Right time complexity: O(n-mid)
- S3 time complexity: O(n)
Algorithm analysis diagram
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 10000;
int q[N]; // 序列
// 求跨越中间的最大子序列
int findMidSum(int l, int mid, int r) {
int leftSum = -100000, rightSum = -100000; // 初始化为 -100000 是为了防止出现负数和的情况
int sum = 0; // sum 即向左和向右最大的子序列的和
for (int i=mid; i>=l; i--) {
sum += q[i];
// 从mid开始向左加不断更新最大值,最后计算出来的即mid左边最大的子序列的值
leftSum = max(leftSum, sum);
// max()函数为 #include<algorithm>中的方法,可以比较两个数的大小,返回较大的数
}
sum = 0;
for (int i=mid+1; i<=r; i++) {
sum += q[i];
// 从mid开始向右加不断更新最大值,最后计算出来的即mid右边最大的子序列的值
rightSum = max(rightSum, sum);
}
return leftSum + rightSum;
}
// 分治求左右两端最大的子序列和并将其与跨越中间的子序列的和比较大小,返回最大连续子序列的和
int maxSubArr(int l, int r) {
if (l == r) return q[l]; // 递归出口
int mid = l + r >> 1; //右移一位,相当于除2;也可以写成 mid = l+(r-l)/2;
int leftSum = maxSubArr(l, mid);
int rightSum = maxSubArr(mid+1, r);
int midMaxSum = findMidSum(l, mid, r);
int res = max(leftSum, rightSum);
res = max(res, midMaxSum);
// 返回最大的子序列和
return res;
}
int main() {
int n;
cin >> n;
for (int i=0; i<n; i++) scanf("%d", &q[i]);
int res = -100000;
res = maxSubArr(0, n-1);
cout << res;
return 0;
}