最大子序列
分类于:算法
发布于:2018-01-10
在数据结构与算法分析一书中讲到了找最大子序列的几种算法,记录如下:
方法一
此方法最直观,当然也比较慢,复杂度 O(N^2)
int max_sub_sum(const vector<int> &a) {
int max_sum = 0;
for (int i = 0; i < a.size(); i++) {
int this_sum = 0;
for (int j = i; j < a.size(); j++) {
this_sum += a[j];
if (this_sum > max_sum) {
max_sum = this_sum;
}
}
}
return max_sum;
}
方法二
采用分治方法,将整个序列不断切分成原来的一半,找到前半部分和后半部分的最大子序列之和,再从中间向两端找最大子序列之和,三者取最大值。复杂度 O(NlogN)
[........................]
<--前半部分--><--后半部分-->
<--中间部分-->
int max_sum_rec(const vector<int> &a, int left, int right) {
if (left == right) {
if (left < 0) {
return 0;
}else {
return a[left];
}
}
int center = (left + right) / 2;
int max_left_sum = max_sum_rec(a, left, center);
int max_right_sum = max_sum_rec(a, center +1, right);
int max_left_border_sum = 0, left_border_sum = 0;
for (int i = center; i >= left; i--) {
left_border_sum += a[i];
if (left_border_sum > max_left_border_sum) {
max_left_border_sum = left_border_sum;
}
}
int max_right_border_sum = 0, right_border_sum = 0;
for (int i = center + 1; i <= right; i++) {
right_border_sum += a[i];
if (right_border_sum > max_right_border_sum) {
max_right_border_sum = right_border_sum;
}
}
int max_sum = max(max_left_sum, max_right_sum);
max_sum = max(max_sum, max_left_border_sum + max_right_border_sum);
return max_sum;
}
int max_sub_sum(const vector<int> &a) {
return max_sum_rec(a, 0, a.size() - 1);
}
注意:没有处理向量长度为奇数的情况。
方法三
此方法异常简洁,而且很好理解。从开头开始累加,一个为负的元素不可能是最大子序列的第一个元素,另外和为负的子序列不可能是最大子序列的前缀,所以当 this_sum
小于 0 时,将其置为 0。复杂度 O(N)。
int max_sub_sum(const vector<int> &a) {
int max_sum = 0;
int this_sum = 0;
for (int i = 0; i < a.size(); i++) {
this_sum += a[i];
if (this_sum > max_sum) {
max_sum = this_sum;
} else if(this_sum < 0) {
this_sum = 0;
}
}
return max_sum;
}