首页 > 代码库 > 求最大子数组的和,以及求该最大子数组的起始位置和末尾位置
求最大子数组的和,以及求该最大子数组的起始位置和末尾位置
问题描述:
一个数组,长度为N,数组元素有负有正,如{-1, 4, 6, -3, 7, -3, -3, 9};我们可以清楚的知道最大的子数组应该是4到9,也就是下标1到下标7,和为17。
求解思路:
第一种方法:我们可以用定义1、两个数ThisSum和MaxSum来记录当前数组的和,以及数组的最大和。
2、我们可以用两个for循环来来遍历数组,每一次求出子数组的最大和,每个子数组从0开始,下一次遍历子数组就是从1开始,以此类推。如第一次就【0~N-1】的最大和,第二次就是【1~N-1】,第三次就是【2~N】。。。。
3、这样,每次用ThisSum来记录当前数组的和,MAXSum来记录当前子数组的最大和,与ThisSum比较,取其最大就能求出最大子数组的和。
4、还是看代码吧,这样比较好理解:
int MaxSubArraySum(int a[], int N, int &start, int &end) { int ThisSum, MaxSum, i, j; *start = 0; *end = 0; MaxSum = 0; for (i = 0; i < N; ++i) { ThisSum = 0; for (j = i; j < N; ++j) { ThisSum += a[j]; if (ThisSum > MaxSum) { *start = i; *end = j; MaxSum = ThisSum; } } } return MaxSum; }5、此方法的时间复杂度很明显为(O(N^2))
第二种算法:
思路:我们力求一种逼格最高的方法使得时间复杂度为(O(N)).
1、同样我们ThisSum来记录当前子数组的和,MaxSum来记录当前子数组最大和,我们可以从0位置开始便来,开始遍历每次ThisSum 加上 a[ i ],如果当前ThisSum大于MaxSum的话,将ThisSum的值付给MaxSum,如果当前的ThisSum<0的话就把ThisSum的值赋值为0,接着下一步的遍历。
2、这里我必须说一下,求最大子数组的起点到尾端的求法,
a、我们定义start 和end来记录
b、当thisSum > maxSum时记录end 等于此时的下标。
c、当thisSum < 0时,我们可以知道起点必须从新修改,改为下一个下标(i +1)为起点start,但是要小心下一个下标(i+1)可能元素的值小于0,或者越界,所以我们必须判断一下。如:
if(i <= arr.length - 2 && arr[i+1] > 0){
start = i + 1;
}
start = i + 1;
}
我们可以写出代码:
int maxSubArraySum(int[] arr, int N, int &start, int end) { int maxSum = 0; int thisSum = 0; int i; *start = 0; *end = 0; for (i = 0; i < N; i++) { thisSum += arr[i]; if (thisSum > maxSum){ maxSum = thisSum; *end = i; } if (thisSum < 0){ thisSum = 0; if(i <= N - 2 && arr[i+1] > 0){ *start = i + 1; } } } //如果最大子数组不在数组里面的话(数组元素全部<=0),start,end赋值为-1 if(*start == 0 && *end == 0 && arr[0] <= 0){ *start = -1; *end = -1; } return maxSum; }
时间复杂度为(O(N))逼格满满有木有=_=
最后一点总结:
在《数据结构与算法分析:C语言描述》中的第二章就出现这一道题,作者从(O(N^3))一路杀到(O(N)),不得不佩服啊,有用循环和递归都有,今天我只讲两种比较典型的方法。
还有的就是作者没有求出子数组的起点以及末端,我就装逼求了一下,哈哈。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。