问题:给定一个数组,有正有负,求它的一个子数组,使得数组里的元素和最大
1. Kadane算法
leetcode: 918. Maximum Sum Circular Subarray
int maxSubarraySumCircular(vector<int> &v) {
// mx:最大子数组和,s:以当前元素结尾的子数组最大和
// mn:最小子数组和,s2:以当前元素结尾的子数组最小和
int mx = v[0], s = v[0], mn = v[0], s2 = v[0], sum = v[0];
for (int i = 1, n; i < v.size(); ++i) {
n = v[i];
sum += n;
if (s <= 0)s = n;
else s += n;
mx = max(mx, s);
if (s2 >= 0)s2 = n;
else s2 += n;
mn = min(mn, s2);
}
if (mx < 0)return mx; // 若数组全为负,则返回最大和
return max(mx, sum - mn);
}
2. 分治法
vector<int> max_subarray(vector<int> &v, int low, int mid, int high) {
int sum = v[mid], start = low, end = high;
for (int i = mid - 1, s = sum; i >= low; --i) {
s += v[i];
if (s > sum) {
sum = s;
start = i;
}
}
for (int i = mid + 1, s = sum; i <= high; ++i) {
s += v[i];
if (s > sum) {
sum = s;
end = i;
}
}
return {start, end, sum};
}
vector<int> max_subarray(vector<int> &v, int low, int high) {
if (low == high)return {low, high, v[low]};
vector<int> result;
int mid = (low + high) / 2;
vector<int> left = max_subarray(v, low, mid); //注意这里包含mid
vector<int> right = max_subarray(v, mid + 1, high);
vector<int> mid_result = max_subarray(v, low, mid, high);
if (mid_result[2] >= left[2] && mid_result[2] >= right[2])return mid_result;
if (left[2] >= right[2])return left;
return right;
}
Reference
-
《算法导论》4.1节