编程之美读书笔记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 - 子数组之和的最大值相关推荐
- 编程之美-2.14-求数组的子数组之和的最大值
这个以前写过,见求数组的最长子数组之和的最大值 这里说一下后面扩展题目. 1. 简述 1) 如果数组首尾相连,即允许找到一组数字(A[i],···,A[n-1], A[0],···, A[j]),请使 ...
- 编程之美 2.14求数组的子数组之和的最大值
对于一个有N个元素的数组,a[0]~a[n-1],求子数组最大值. 如:数组A[] = [−2, 1, −3, 4, −1, 2, 1, −5, 4],则连续的子序列[4,−1,2,1]有最大的和6. ...
- 《团队开发一(求一个数组的连续的子数组之和的最大值)》
<团队开发一(求一个数组的连续的子数组之和的最大值)> (1)设计思想:一般的,求一个数组的最大子数组之和即是按数组顺序依次让前几个数的和与下一个数进行比较,设一变量来装每次比较后的较大的 ...
- 求数组的子数组之和的最大值
一个有N个整数元素的一维数组( A[0], A[1], ... , A[n-2], A[n-1]),子数组之和的最大值是什么?(要求子数组的元素是连续的) 例子:有数组( -2, 5, 3, -6, ...
- 【C】课堂结对联系-求整数数组的子数组之和的最大值(党云龙、黄为)
测试题目 求整数数组的子数组之和的最大值. 题目分析 首先是明确题目的目的:求最大值:其次是考虑子数组求和.这里将求最大值写成一个单独的函数.主函数未测试函数.这里用到了二重循环,时间复杂度为N^2. ...
- 算法-求数组的子数组之和的最大值
一个一维int数组,这个数组有很多子数组,那么子数组之和的最大值是什么呢? 思考 1.题目说的子数组是连续的: 2.题目只需要求和,并不需要返回子数组的具体位置: 3.数组的元素是整数,所以数组可能包 ...
- 编程之美2.14 求数组的子数组之和的最大值
这是一个在面试中出现概率很高的一道题目,就拿我来说吧,面试了5家公司中,两家公司问了这道题目,可见,这道题目是非常经典的. 解题思想也不是很难,我熟悉的有:两种解题办法: ...
- Programe_Of_Beauty:2.14 求数组的子数组之和的最大值
问题:一个有N个整数元素的一维数组,那么求子数组和的最大值. 分析:首先我们明确问题,子数组是联系的,不用返回元素的位置,元素是整数,可能为正,负或0.我们来看看最经典的解法:a[0],a[1]-a[ ...
- 编程之美 - 读书笔记 - 卖书折扣问题的贪心解法
<编程之美>读书笔记(四):卖书折扣问题的贪心解法 每 次看完<编程之美>中的问题,想要亲自演算一下或深入思考的时候,都觉得时间过得很快,动辄一两个小时,如果再把代码敲一遍的话 ...
- 求数组的子数组之和的最大值IV
在之前的基础上又安排了二维数组的,在课上一开始是理解错要求了,简单的以为用循环数组就能解决,但是却忽视了子数组是否能构成矩形,之后课下和同学们讨论,主要是多重遍历,但是我还是没搞明白怎么构成新的二维数 ...
最新文章
- BugKuCTF WEB 网站被黑
- github gists 101使代码共享漂亮
- 前端学习(495):嵌入代码与外部文件和文档模式
- 命令行运行jmeter脚本
- pythonexecquery_python 进程信息
- Linux删除带空格的文件 删除最后一个后缀名
- 印花导带容易出现的问题及其解决方法
- umbrello 用户手册_别克君威车主必备:君威用户手册|君威使用说明书电子版|君威保养手册_搜狐汽车...
- springboot-增加自定义资源映射
- 2022年黑马程序员火爆全网的自学Java必刷教程(价值2w+的教程免费分享)
- Java正则表达式【详解】
- T-Tree索引与MMDB简单映射(草稿)
- Tableau 2018.2 安装与破解记录
- JBX IDE中文输入
- SRCNN:Image Super-Resolution Using Deep Convolutional Networks
- 每个汉字在DB2数据库中占多少个字节?
- 2022牛客多校联赛第九场 题解
- 映射和反射的概念及应用方法
- 课堂在线录屏:EV录屏软件配置设置
- java Swing实现图书管理系统