连续性问题有哪些,求最大连续数
给出一个长度为n的序列A 1,A 2,…,n,求最大连续和。换句话说,要求找到1=i=j=n,使得阿伊阿伊1…阿j尽量大。暴力枚举实现#包括输入输出流
使用命名空间标准
int A[50]={5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7 };
int main()
{
int n=50
int tot=0;
int best=A[0];
//初始化最大值,为了防止连续和小于0,所以必须初始化为一个[0].
for(int I=0;I n;我)
{
for(int j=I;j n;j)
{//检查连续子序列A[i],…,A[j]
int sum=0;
for(int k=I;k=j;k)
{//累加元素和
sum=A[k];
小孩
}
如果(最佳求和)
{
最佳=总和;
}
}
}
cout best= best tot= tot endl;
返回0;
}tot与机器的运行速度无关。
不同机器的速度不一样,运行时间也会有所差异,但小孩的值一定相同。
换句话说,它去掉了机器相关的因素,只衡量算法的"工作量"大小,
具体来说,是"加法"操作的次数。
算法分析:1.第一层循环遍历数组A的我位从0到n,是最大连续和的左起点;
2.第二层循环遍历数组A的j位从我到n,是最大连续和的右终点;
3.第三层循环遍历数组A的k位从我到j,求出当前范围内的连续和;
4.公式:设输入规模为n时的加法操作次数
连续子序列之和等于两个前缀和之差实现#包括输入输出流
使用命名空间标准
int A[50]={5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7 };
int S[50];
int main()
{
int n=50,best=A[0];
s[0]=0;
for(int I=0;I n;我)
{
S[I]=S[I-1]A[I];
//递推前缀和S
}
for(int I=0;I n;我)
{
for(int j=I;j n;j)
{
best=max(best,S[j]-S[I-1]);
//更新最大值
}
}
cout best= best endl
返回0;
}算法分析:S[i]表示第一个数到第我个数的和S[j]-S[i-1]表示第我个数到第j个数列的和。
分治算法实现#包括输入输出流
使用命名空间标准
int A[50]={5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7 };
int maxsum(int *A,int x,int y)
{//返回数组在左闭右开区间[x,y]中的最大连续和
如果(y-x==1)返回一个[x];//只有一个元素,直接返回。
int m=x(y-x)/2;
//分治第一步:划分成[x,m]和[m,y]
int maxs=max(maxsum(A,x,m),maxsum(A,m,y));
//分治第二步:递归求解
int v,L,R;
v=0,L=A[m-1];
//分治第三步:合并(1)——从分界点开始往左的最大连续和L
for(int I=m-1;I=x;我-)
{
L=max(L,v=A[I]);
}
v=0,R=A[m];
//分支第三步:合并(2)——从分界点开始往右的最大连续和稀有
for(int I=m;I y;我)
{
R=max(R,v=A[I]);
}
return max(maxs,L R);//把子问题的解与L和稀有比较
}
int main()
{
cout maxsum(A,0,51)endl;
返回0;
}分治算法实现:
1.划分问题:把序列分成元素个数尽量相等的两半;
2.递归求解:分别求出完全位于左半或者完全位于右半的最佳序列;
3.合并问题:求出起点位于左半,终点位于右半的最大连续和序列,并和子问题的最优解比较。
思路分析首先,我们可以把整个数列平均分成左右两部分,答案则会在以下三种情况中:
1、所求数列完全包含在左半部分的数列中。
2、所求数列完全包含在右半部分的数列中。
3、所求数列刚好横跨分割点,即左右数列各占一部分。
前两种情况和大问题一样,只是规模小了些,如果三个子问题都能解决,那么答案就是三个结果的最大值。
计算出:以分割点为起点向左的最大连续数列和、以分割点为起点向右的最大连续数列和,这两个结果的和就是第三种情况的答案。因为已知起点,所以这两个结果都能在O(N)的时间复杂度能算出来。
算法分析:用递归的思路进行分析,设序列长度为n时T(n)=2T(n/2) n,T(1)=1;
其中2T(n/2)是两次长度为n/2的递归调用,而最后的n是合并的时间(整个序列恰好扫描一遍)。
注意分界点应当是x和y的平均数m=x (y-x)/2,这是因为运算符"/"的"取整"朝零方向(趋向于零)
圆形,不是圆形向下。使用x (y-x)/2确保边界点总是靠近间隔的开始。
#include iostream的动态规划和实施
使用命名空间std
int A[50]={0,5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7 };
int main()
{
int ans=A[1];
for(int I=1;i 50我)
{
if(A[I-1]0)A[I]=A[I-1];
else A[I]=0;
if(A[I]ans)ans=A[I];
}
cout ans endl
返回0;
}算法分析用dp[n]表示以第n个数结尾的最大连续子序列之和,所以有如下递推公式:
dp[n]=max(0,dp[n-1]) num[n]
整个问题的答案是max(dp[m]) m[1,N]。
大道至简3354完美解决方案实现#包括iostream
使用命名空间std
int main()
{
int N,N,s,ans,m=0;
CIN N N;//读取数组长度和序列中的第一个数字
ans=s=n;//将ans初始化为序列中的第一个数字
for(int I=1;I N;我)
{
if(s m)m=s;
CIN n;s=n;
如果(s-m ans)
ans=s-m;
}
cout ans endl
返回0;
}给定一个sum数组,sum[i]表示第1个数到第I个数的和,所以sum[j]-sum[i-1]表示第I个数到第j个数的和。
以第n个数结尾的最大子序列。假设这个子序列的起点是M,结果是sum[n]-sum[m-1]。
并且,sum[m]必须是sum[1],sum[2]…sum[n-1]中的最小值。
这样,如果在保持计算的和数组的同时,保持前面的最小值,那么答案就出来了。
在计算前缀和的过程中,保持之前获得的最小值。
其时间复杂度为O(N),空间复杂度为O(1),达到理论下限!
大连,最后一个问题,解决了!
转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。