最大连续子数组和与最大连续子矩阵和
来源:互联网 发布:羽毛球鞋 推荐 知乎 编辑:程序博客网 时间:2024/06/16 20:33
这两个问题是编程中常见的问题,而且网上有大量博客论述,这里主要是自己做一个笔记。两个之间是有关系的,所以这次放在一起复习
- 最大连续子数组
先看第一个问题:
给定一个整数数组,数组里面可能有正数,负数、零。数组中的一个或多个连续数组构成一个子数组,每个子数组都有一个和,求所有子数组和的最大值。
例子:数组a[]={1,-2,3,10,-4,7,2,5}.那么和最大的子数组为{3,10,-4,7,2},所以结果输出18.
求解:
思路一:暴力法
找出数组的所有子数组,然后求组所有子数组中和最大的,其中确定一个子数组需要起始位置和终止位置,所以这一步的复杂度是
思路二:动态规划方法
假设给你一个数组
然后告诉你
那么最大子数组的和就是:
还是上面的例子,
所以程序中需要两个变量,一个是以
函数代码如下:
int maxSubArray(int a[],int n){ int maxSum=0; int currSum=0; for(int i=0;i<n;i++) { if(currSum>=0) currSum+=a[i];//更新currSum else currSum=a[i]; if(currSum>maxSum) maxSum=currSum;//更新maxSum } return maxSum;}
整个过程中currSum和maxSum更新如下:
拓展
- 如果要求求出最大连续子数组的和,并且同属输出所求子数组的开始位置和起始位置?
分析:这个问题还是比较好解决的,只要清楚什么最大子数组开始的条件和结束的条件就可以了,可以设置几个flag,其中开始点应该是currSum由负数变正数,且currSum大于maxSum的时候。而结束的时候应该是currSum大于maxSum且由正数变为正数。 - 如果要求出最大子数组的和,但不要求子数组是连续的呢?
分析:这个好办,大于0的数相加即可。 - 如果是二维数组,同样要求求出最大连续子数组的和呢?
针对第三个问题,引申出下面第二个问题:
给定一个M×N 的矩阵,找出此矩阵的一个子矩阵,要求满足这个子矩阵的元素和是最大的,输出这个最大值,如果所有数是负数,就输出0.
例如:给定一个
它的和最大子矩阵是:
最后输出和的最大值为17.
当然这里要求的是一个方阵,还有一种更一般的是矩阵中有正有负,对于子矩阵的大小也没有要求:
那么最大子矩阵是:
那么如何求解这个问题呢?
如果采用暴力法——遍历所有子矩阵,那么需要找出所以子矩阵,确定子矩阵需要四个参数,左上角两个,右下角两个所以有
我们在前面已经说到过,最大连续子数组和最大连续子矩阵的和这个问题是有相关性的。当我们确定矩阵的哪几行时,我们如何确定哪几列呢?,例如当我们要选取2,3,4行时,我们需要决定选取那几列的时候,我们只要将这个三行相加,得到一个一维数组,那么就可以用上一个问题的方法去解决了。
所以思路就是:我们遍历所有的行的组成情况,然后将选出来的行按列相加,构成一个一位数组的最大连续子数组问题。
int maxSubMatrix(int a[],int m,int n)//二维数组以一位数组的形式存放,m和n分别代表矩阵的行和列{ int max=0; int sum=-10000; //选择一个足够小的数 int* p=new int[n]; //开辟一个用于存放和的一位数组 for(int i=0;i<m;i++) { memset(p,0,sizeof(int)*n); //赋初值为0 for(int j=i;j<m;j++) { for(int k=0;k<n;k++) { p[k]+=a[j*n+k]; //累加求和 } max=maxSubArray(p,n); //调用一维数组的方法 if(max>sum) sum=max; } } delete [] p; return sum;}
测试:
int main(){ int s[]={0,-2,-7,1,9,2,-6,2,-4,1,-4,1,-1,8,0,-2}; cout<<maxSubMatrix(s,4,4)<<endl; return 0;}
结果是:15
延伸问题:长度最短连续子序列问题
有一个长度为n 的正整数序列,现给定一个整数S,要求求出序列中长度最短的一个连续序列,且序列的和大于等于S。
分析:可以直接用两个for循环枚举所有子序列的起点和终点,但这种方法的时间复杂度为$O(n^3)$,需要找到更好的办法。其实,因为都是正数,所以当从第一个数开始累加,累加到大于S的时候,开始删掉前面的数,直到小于S,然后把后面的数加进来,这样遍历一遍就能解决掉。
int LessSeq(const int a[],int N,int s){ int start,end,sum; start=end=sum=0; int L=N+1; while(end<N) { if(sum<s) sum+=a[end]; while(sum>=s) { sum-=a[start]; L=min(L,end-start+1); start++; } end++; } return L;}
- 最大连续子数组和与最大连续子矩阵和
- 最长连续和与最大子矩阵
- 连续子数组最大和
- 连续最大子数组和
- 连续子数组最大和
- 最大连续子数组和
- 连续子数组最大和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和
- 最大连续子数组和。
- 最大子数组和(连续)
- 最大连续子数组和
- Ajax请求简单封装
- 1249:人见人爱A+B
- 将结构体按位写入文件
- 深入分析Tomcat启动时重复加载项目的原因及解决办法
- 设置Ajax为同步请求
- 最大连续子数组和与最大连续子矩阵和
- Android状态栏渐变色的实现
- openstack常用检查命令杂烩
- Android项目重构-架构篇
- Mysql学习整理(五)
- SSM项目中,普通类中调用Service
- 使用朴素贝叶斯分类器对新闻文本数据进行类别预测
- Java 类 文件 编译
- Boolean.valueOf的用法(字符串转boolean时注意)