1.递归
该方法由书上提供,比较好理解:给定一个数组,从中间划分成两个数组[1,mid],[mid+1,end];最大子序列可分为三种情况:
a.位于左半边
b.位于右半边
c.跨越两边
求两边最大子序列时可递归求解,求跨越两边的子序列时分别从mid、mid+1出发,求得left_sum和right_sum,相加即为跨越两边的最大子序列和。时间复杂度O(nlogn)。
代码:
#include <stdio.h> #include <stdlib.h> int Find_Mid_Max(int* q,int start,int end) { int mid = (start + end) / 2; int left_sum = 0; int right_sum = 0; int sum = 0; int i; for (i = mid;i > 0;i--) { sum += q[i]; if (sum > left_sum) left_sum = sum; } sum = 0; for (i = mid+1;i <=end;i++) { sum += q[i]; if (sum > right_sum) right_sum = sum; } return left_sum + right_sum; } int Find_Max(int* q, int start, int end) { int maxsum = 0; if (start == end) { if (q[end] > maxsum) maxsum = q[end]; return maxsum; } int mid = (start + end) / 2; int left=Find_Max(q, start, mid); int right = Find_Max(q, mid + 1, end); int across = Find_Mid_Max(q, start, end); if (left > right && left > across) maxsum = left; else if (right > across) maxsum = right; else maxsum = across; return maxsum; } int main() { int k; if (scanf("%d", &k) == 0){} int* q = (int*)malloc(sizeof(int) *(k+1)); int i; for (i = 1;i <= k;i++) { if(scanf("%d",&q[i])==0){} } int max=Find_Max(q, 1, k); printf("%d", max); return 0; }
2.在线处理
从第一个元素开始遍历整个数组,用tempsum暂时记录当前子序列的和。如果加上一个元素之后,tempsum<0了,那么包含这个元素再继续往后加的子序列一定不可能是最大的,因为负数总是对这个子序列产生消极的影响,所以我们可以舍弃这个序列,从下一个序列开始再次寻找。用maxsum记录最大值,若tempsum>maxsum则更新。还要记录最大子序列的开始和结束点(具体见代码,有些地方是题目里要求的)。时间复杂度O(n)。
代码:
#include <stdio.h> #include <stdlib.h> int* Find_Max(int* q, int start, int end) { int *ret=(int *)malloc(sizeof(int)*3); ret[0] = 0;//记录最大和 ret[1] = start;//开始下标 ret[2] = 0;//结束下标 int tempsum = 0; int temps = 0; int i; int neg = 0; int pos = 0; int zer = 0; for (i = 0;i < end;i++) { if (q[i] > 0) pos = 1; if (q[i] < 0) neg = 1; if (q[i] == 0) zer = 1; tempsum += q[i]; if (tempsum < 0) { tempsum = 0; temps = i + 1; } else { if (tempsum > ret[0]) { ret[0] = tempsum; ret[1] = q[temps]; ret[2] = q[i]; } } } if (!pos&&neg&&!zer) { ret[1] = q[start]; ret[2] = q[end-1]; } else if (!pos && neg && zer) { ret[1] = start; ret[2] = 0; } return ret; } int main() { int k; if (scanf("%d", &k) == 0){} int* q = (int*)malloc(sizeof(int) *k); int i; for (i = 0;i < k;i++) { if(scanf("%d",&q[i])==0){} } int *ret=Find_Max(q, 0, k); printf("%d %d %d", ret[0],ret[1],ret[2]); return 0; }