首页 > 代码库 > 编程之美读书笔记2.14 - 子数组之和的最大值
编程之美读书笔记2.14 - 子数组之和的最大值
http://blog.csdn.net/pipisorry/article/details/39083281
问题:
1. 一个由N个整数元素的一维数组,求其所有子数组中元素和的最大值。2. 如果数组首尾相邻,也就是允许子数组A[i],...,A[n-1],A[0],...,A[j]存在,求其所有子数组总元素和的最大值。
解法1:
/* O(n^2) 遍历算法 */ static int maxSubarraySum1(int *a,int a_len){ int max_sum = INT_MIN, sum; for(int i = 0; i < a_len; i++){ //从i开始的子数组的最大和,遍历所有情况 sum = 0; for(int j = i; j < a_len; j++){ sum += a[j]; if(sum > max_sum) max_sum = sum; } } return max_sum; }
解法2:
/* O(nlogn) 分治算法 */ static int maxSubarraySum2(int *a, int low, int high){ //a[low] a[high]之间最大子段和 if(low >= high) //只剩一个元素的时候返回本身为最大值 return a[low]; int mid = (high + low) / 2; //以a[mid]结尾的最大一段数组之和 int sum = 0, max_sum_left = INT_MIN; for(int i = mid; i >= low; i--){ sum += a[i]; if(sum > max_sum_left) max_sum_left = sum; } int max_sum_right = INT_MIN; //以a[mid + 1]开始的最大一段数组之和 sum = 0; for(int i = mid + 1; i <= high; i++){ sum += a[i]; if(sum > max_sum_right) max_sum_right = sum; } int max_sum = max_sum_left + max_sum_right; int max_sub_left = maxSubarraySum2(a, low, mid); //数组左段最大子段和 int max_sub_right = maxSubarraySum2(a, mid + 1, high); //数组左段最大子段和 int max_sub = max_sub_left > max_sub_right ? max_sub_left:max_sub_right; max_sum = max_sum > max_sub? max_sum : max_sub; //数组总的最大子段和 return max_sum; }
解法3:
/* O(n) DP算法 */ static int maxSubarraySum3(int *a, int n){ int *start = (int *)malloc(sizeof(a[0]) * n); //start[i]为从i开始的包含a[i]最大子数组和 int *all = (int *)malloc(sizeof(a[0]) * n); //all[i]为从i开始的最大一段数组和 start[n - 1] = a[n - 1]; all[n - 1] = a[n - 1]; for(int i = n - 2; i >= 0; i--){ start[i] = start[i + 1] + a[i] > a[i]? start[i + 1] + a[i] : a[i];//start[i] = max{a[i], start[i+1]+a[i]} all[i] = start[i] > all[i + 1] ? start[i] : all[i + 1]; //all[i] = max{start[i], all[i+1]} } return all[0]; } /* O(n) DP算法(O(1)空间) */ static int maxSubarraySum4(int *a, int n){ int start = a[n - 1]; int all = a[n - 1]; for(int i = n - 2; i >= 0; i--){ start = start + a[i] > a[i]? start + a[i] : a[i]; all = start > all ? start : all; } return all; }
解法4:
/* O(n) 最优算法 */ /* 最优的解是只扫描数组一遍,因此时间为 O(n)。假设 x1, x2, ..., xt 是最优解。 那么,显然, 对任何 i <= t,x1, x2,..., xi 之和不可能为负。 否则,砍去这一段,我们可以得到更大的值,这些该段的最优性矛盾。 这就是说,最优解的段前缀不可能为负。而换句话说,如果一个段的和为负,则不可能是最优解的一部分。 一开始,令当前段为从 x1 开始的段,置为空。我们从数组开始向前搜索,并把遇到的数加入当前段 s,同时记录目前遇到的最大和。 这个过程一直持续到加入某个数 xi,使得 s 之和为负,则清空 s,然后以 xi 的下一个元素为当前段的开始,继续向前搜索。 重复这个过程直到数组结束。在实现时,并不需要维护集合 s 并每次都对其对和,而只需要维护一个当前段的和, 当有新元素加入当前段时,更新段的和;当重新开始一个段时,清 0 该段之和。 */ static int maxSubarraySum(int *a, int n){ int sum = 0, max_sum = INT_MIN; for(int i = 0; i < n; i++){ sum += a[i]; if(sum > max_sum) max_sum = sum; if(sum < 0) //前缀<0时可以去掉sum的累积和 sum = 0; } return max_sum; } /* O(n) 最优算法(记录左右边界) */ static int maxSubarraySum5(int *a, int n){ int sum = 0, max_sum = INT_MIN; int max_low = 0, max_high = 0; //最优子数组左右边界 int low = 0; //当前非<0前缀的子数组首下标 for(int i = 0; i < n; i++){ sum += a[i]; if(sum > max_sum){ max_sum = sum; max_high = i; max_low = low; } if(sum < 0){ //前缀<0时可以去掉sum的累积和 sum = 0; low = i + 1; } } printf("max_low = %d, max_high = %d\n", max_low, max_high); return max_sum; }
测试:
//***************************************************************************************/ //* 编程之美2.14 —— 求数组的子数组之和的最大值(微软亚研2006) 皮皮 2014-9-4 */ //***************************************************************************************/ #include <stdio.h> #include <assert.h> #include <malloc.h> #include <limits.h> int main(){ assert( freopen("BOP\\maxSubarraySum.in", "r", stdin) ); int cases; //测试案例数目 scanf("%d", &cases); while(cases--){ int n; //每个案例中数组元素个数 scanf("%d", &n); int *a = (int *)malloc(sizeof(int) * n); for(int i = 0; i < n; i++) scanf("%d", &a[i]); printf("%d\n", maxSubarraySum1(a, n)); printf("%d\n", maxSubarraySum2(a, 0, n - 1)); printf("%d\n", maxSubarraySum3(a, n)); printf("%d\n", maxSubarraySum4(a, n)); printf("%d\n", maxSubarraySum(a, n)); printf("%d\n\n", maxSubarraySum5(a, n)); } fclose(stdin); return 0; }
测试案例:
4
7 -2 5 3 -6 4 -8 6
6 1 -2 3 5 -3 2
6 0 -2 3 5 -1 2
5 -9 -2 -3 -5 -3
answer:
8 [1 - 2]
8 [2 - 3]
9 [2 - 5]
-2 [1 - 1]
from:
http://blog.csdn.net/pipisorry/article/details/39083281
ref:
http://blog.csdn.net/pipisorry/article/details/39048485
编程之美读书笔记2.14 - 子数组之和的最大值
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。