最大连续子串问题
首先,要明白子串和子序列的区别。
1)子串(Substring)是串的一个连续的部分;
2)子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列;(关于求最长子序列的算法见博客:动态规划(5)-字符串相似度算法))
最大连续子串问题是给定一组元素,求使得连续子串的值最大,比如最大连续和子串、最大连续乘积子串。这类问题可以用动态规划求解。下面举例说明如何求解这类问题。
最大连续和子串
例子:输入一个整型数组,数组里有正数也有负数。数组中一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
算法1:时间复杂度O(n*n)maxsofar=pData[0];
for i=[0,n)
sum=0;
for j=[i,n){
sum+=pData[j];
maxsofar=max(maxsofar,sum);
}//end for
算法2:动态规划,时间复杂度O(n)假设f[i-1]是i-1时的最优解,则如何求f[i]时的最优解呢?
此时f[i]面临2种选择:一是与前面子数据相加,二是不与前面子数据相加,即f[i]=pData[i]。具体的:
当f[i-1]<=0时,如果把负数与pData[i]相加,得到的结果比pData[i]本身还要小,所以此时f[i]=pData[i]f[i]=f[i-1]+pData[i]
public int maxSubArray(int[] pData)throws Exception{
//输入控制
if(pData==null)
throw new Exceptin("input can not be null");
n=pData.length;
if(n==0)
throw new Exceptin("have no data,must have one element");
//只有一个数字的情况
if(n==1)
return pData[0];
//初始化
int[] f=new int[n]; //用数组f保存计算过程中的值
f[0]=pData[0];
int maxsofar=f[0]; //用maxsofar保留当前最大值
for(int i=1;i
相关题目:如果希望查找一个总和最接近某一给定实数(如t)的子向量,假设函数absolute(a)用于求a的绝对值,则
absoluteT=absolute(t)
f[i]的值应该满足以下条件:
min{ absolute( absolute(f[i-1]+pData[i]) - absoluteT ), absolute( absolute(pData[i]) - absoluteT) }
所以,有以下递推关系
当absolute( absolute(f[i-1]+pData[i]) - absoluteT )>= absolute( absolute(pData[i]) - absoluteT)时,f[i]=pData[i]
当absolute( absolute(f[i-1]+pData[i]) - absoluteT ) < absolute( absolute(pData[i]) - absoluteT)时,f[i]=f[i-1]+pData[i]
同时用nearT记录f中最接近t的那个总和
最大乘积连续子串
例子:问题:题目描述:给一个浮点数序列,取最大乘积连续子串的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8=12是最大的,而且是连续的。
【算法一】分析:动态规划类似于上述解法,其递归解如下:
当i=0时,f[i]=pData[i]
当i!=0时,
1)当f[i-1]>1时,f[i-1]=f[i-1]*pData[i];
2)当0
当pData[i]>=0时,f[i-1]=pData[i];
当pData[i]<0时,f[i-1]=f[i-1]*pData[i];
3)当f[i-1]=0时,
当pData[i]>0时,f[i-1]=pData[i];
当pData[i]<=0时,f[i-1]=f[i-1]*pData[i];
4)当f[i-1]<0时,
当pData[i]>0时,f[i-1]=pData[i];
当pData[i]<0时,f[i-1]=f[i-1]*pData[i];
【算法二】递归公式如下(参考自July最大乘积子串):
假设数组为a[],考虑到可能存在负数的情况,我们用Max来表示以a结尾的最大连续子串的乘积值,用Min表示以a结尾的最小的子串的乘积值,那么状态转移方程为:
Max=max{a, Max[i-1]*a, Min[i-1]*a};
Min=min{a, Max[i-1]*a, Min[i-1]*a};
初始状态为Max[1]=Min[1]=a[1]。
double func(double *a,const int n)
{
double *maxA = new double[n];
double *minA = new double[n];
maxA[0] = minA[0] =a[0];
double value = maxA[0];
for(int i = 1 ; i < n ; ++i)
{
maxA[i] = max(max(a[i],maxA[i-1]*a[i]),minA[i-1]*a[i]);
minA[i] = min(min(a[i],maxA[i-1]*a[i]),minA[i-1]*a[i]);
value=max(value,maxA[i]);
}
return value;
}
算法:如果允许对数组排序的话,先排序数组,然后从第一个正数开始,转换为求“最大连续乘积子串”的问题。时间复杂度O(n+nlogn)