1->求连续子序列的最大和问题。例如【0,-2,3,5,-1,2】返回值9。
*解题方法:这是动态规划算法的经典题目:该算法的过程描述为,只要前i项的和还没有小于0,那么子序列就一直往后扩展,否则丢弃之前的子序列开始新的子序列。同时我们也要记录下各个子序列的和,以便求出子序列和的最大值。
int MaxSum(int A[],int n){
int Maxsum=INT_MIN;
int sum=0;
for(int i=0;i<n;i++){
if(sum>=0) sum+=A[i];
else sum=A[i];
if(sum>Maxsum) Maxsum=sum;
}
return Maxsum;
}
另外要注意该题目对最大和为负数的处理方法是直接返回0.如果题目要求对最大和为负数的时候返回最小负数。那么就在返回结果之前,采用顺序查找的方式,在数组里面找出最小负数,然后将其返回。
2->对于上述的题目,如果题目要求保存最大和子序列的开始位置和结束位置?
解题方法:将上述的代码稍微作下修改,即可
int MaxSum_Locate(int A[],int n,int &start,int &end){
int Maxsum=INT_MIN;
int sum=0; start=end=0;
int curlocate=0;
for(int i=0;i<n;i++){
if(sum<0){sum=A[i]; curLocate=i;}
else sum+=A[i];
if(sum>MaxSum){
MaxSum=sum; start=curLocate; end=i;
}
return Maxsum;
}
}
3->连续子序列的最大和,也可以采用分治的算法。对于一个数组求子序列的最大和,只有三种情况:1):最大和出现在数组的右半部分 2):最大和出现在数组的左半部分 3):跨越了两个部分
下面就给出连续子序列的最大和的分治算法求解:
int MaxSumRec(const vector<int> & A,int left,int right){
if(left==right){
if(A[left]>0) return A[left];
else return 0;
}
int mid=(left+right)/2;
int maxLeft=MaxSumRec(A,left,mid);
int maxRight=MaxSumRec(A,mid+1,right);
int leftTmp=0,rightTmp=0;
int maxLeftTmp=0,maxRightTmp=0;
for(int i=mid;i>=left;i--){
leftTmp+=A[i]; if(leftTmp>maxLeftTmp) maxLeftTmp=leftTmp;
}
for(int i=mid+1;i<=right;i++){
rightTmp+=A[i]; if(rightTmp>maxRightTmp) maxRightTmp=rghtTmp;
}
return Max(maxLeft,maxRight,maxLeftTmp+maxRightTmp);
}
4->最长递增子序列
解题方法1:动态规划的求解方法:根据分析可以知道第i个元素的最长递增序列要么是1,那么是第i-1个元素之前的元素的最长递增加1.
int Lis(int A[],int n){
int *dp=new int[n];
for(int i=0;i<n;i++) dp[i]=1; //动态规划数组初始化
for(int i=1;i<n;i++)
for(int j=0;j<i;j++){
if(A[i]>A[j] && dp[i]<dp[j]+1) dp[i]=dp[j]+1;
}
int ret=0;
for(int i=0;i<n;i++) if(dp[i]>ret) ret=dp[i];
return ret;
}
解题方法2:转化为求最长公共子序列问题:将原来的数组排序,排序后的数组与原来数组的最长公共子序列,就是最大递增序列
int LCS(int A[],int n){
int *B=new int[n];
copy(A,A+n,B); sort(B.B+n);
int **dp=new int*[n];
for(int i=0;i<n;i++) dp[i]=new int[n]();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(A[i]==B[j]) d[i][j]=dp[i-1][j-1]+1;
else if(dp[i-1][j]>dp[i][j-1]) dp[i][j]=dp[i-1][j];
else dp[i][j]=dp[i][j-1];
}
return dp[n-1][n-1];
}
5->最长公共子串问题
int LCS(const int *str1,int len1,const char *str2,int len2,char *&lcs){
if(str1==NULL || str2==NULL) return -1;
int *c=new int [len2]();
int max_len=0; int end=0;//保存最大公共子串的末尾位置
for(int i=0;i<len1;i++)
for(int j=len2-1;j>=0;j--){
if(str1[i]==str2[j]){
c[j]=c[j-1]+1;
if(c[j]>max_len){max_len=c[j]; end=j;}
}else {
c[j]=0;
}
}
if(max_len==0) return 0;
//得到公共子串
lcs=new char[max_len+1];
for(int i=0;i<max_len;i++) lcs[i]=str2[end-max_len+1-i];
lcs[max_len]='\0';
return max_len;
}
6->最长公共子序列问题
解题方法:递归的方式求解问题:设字符串a[0....n],b[0.....m],则易知当a[i]与b[j]相同时,则求两个串从下一个位置开始剩下部分的最长公共子序列即可,当u相同时,最长公共子序列表示为LCS(i,j+1)和LCS(i+1,j)中两则较大的。
Code:
int LCS(int &A[],int i,int &B[],int j){
if(i>=A.size() ||j>=B.szie()) return 0;
if(a[i]==b[j]) return 1+LCS(A,i+1,B,j+1);
else return max(LCS(A,i+1,B,j),LCS(A,i,B,j+1));
}
解题方法2:动态规划方法,采用一个二维数组来保存中间结果
Code:
int LCS(int &A[],int &B[]){
int **dp=new int *[A.Size()+1];
for(int i=0;i<=A.size();i++) dp[i]=new int[B.szie()+1]();
for(int i=0;i<A.size();i++)
for(int j=0;j<B.size();j++){
if(a[i]==b[j]) dp[i+1][j+1]=d[i][j]+1;
else if(dp[i+1][j]>dp[i][j+1]) dp[i+1][j+1]=dp[i+1][j];
else dp[i+1][j+1]=dp[i][j+1];
}
return dp[A.size()][B.size()];
}
如果需要给出具体的子序列,那么就在动态规划算法里面加入一个标记数组flag[n][m],当a[i]==b[j]时,flag[i][j]=1;当取a向前一步是flag[i][j]=2,还有一个等于3.取最长子列的程序:
void getLCS(vector<char> &lcs){
int i=a.size(),j=b.size();
while(i>0 &&j>0){
if(flag[i][j]==1){ lcs.insert(lcs.begin(),a[i-1]);i--;j-- ; }
else if(flag[i][j]==2) i--;
else j--;
}
print(lcs.begin(),lcs.end());
}
7->字符串编辑距离问题:给一个源字符串和,目标字符串,能够对源串进行:在给定位置插入一个字符,替换一个字符,删除一个字符。求源串到目的串的最小步长
解题方法:最小编辑距离问题的递归式:f(i,j)=MIN(f(i-1,j)+1 , f(i,j-1)+1, f(i-1,j-1)+(strA[i]==strB[j]?0:1));
Code:
/*C数组被初始化为INT_MIN*/
int EDM(char *&strA,int i,char *&strB,int j){
if(i>strA.size() || j>strB.size()){
if(i>strA.size() && strB.size()) {return 0;}
else return MAX(strA.size()-i+1,strB.size()-j+1);
}
int a1=0,a2=0;
if(strA[i]==strB[j])
a1=EDM(strA,i+1,strB,j+1);
else{
int b1=EDM(strA,i+1,strB,j);
int b2=EDM(strA,i,strB,j+1);
int b3=EDM(strA,i+1,strB,j+1);
a2=min(b1,b2,b3)+1;
}
return min(a1,a2);
}