本文主要讲的算法题是关于两个字符串A和B,求A在B中出现的次数,并且不要求A中的所有字符在B中连续出现,例如A=ab,B=abadcb,那么结果为3.
首先,我们假定:假如A为空字符串,B为非空,那么次数为1。而如果B为空字符串,那么次数为0。用L(i,j)表示A的i个字符在B的j个字符中出现的次数。除了之前的假定,我们现在动态地观察规律,假如A[i]=B[j]那么需要看A的前i-1个在B的前j-1个的包含的个数,以及A前i个在B的前j-1个字符中出现次数(因为出现A=ab,B=abb的情况),所以当A[i]=B[j]:L(i,j)=L(i-1,j-1)+L(i,j-1)。而当A[i]!=B[j]时,那么要保证前A的前i个在B的前j个字符出现次数,只要求A的前i个在B的前j-1个出现的次数的子问题就行(因为第i个不等于第j个字符),因此当A[i]!=B[j]:L(i,j)=L(i,j-1)。
因此,根据上述的分析,得到如下代码:
import java.util.*;
public class Counting {
public static int counting(String s1,String s2)
{
int m=s1.length();
int n=s2.length();
int[][] count=new int[m+1][n+1];
for(int i=0;i<=m;i++)
{
for(int j=0;j<=n;j++)
{
if(i==0)
count[i][j]=1;
else
count[i][j]=0;
}
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(s1.charAt(i-1)==s2.charAt(j-1))
count[i][j]=count[i-1][j-1]+count[i][j-1];//当前s1第i个字符与s2第j个字符相等,
//所以当前方案取决于i-1个字符与j-1个字符的方案情况以及i个字符在j-1个字符中的情况。因为s2要包含s1,所以是用i个字符去匹配j-1个字符。
else
count[i][j]=count[i][j-1];
}
}
return count[m][n];
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1="ab";
String s2="abadcbbab";
System.out.println(counting(s1,s2));
}
}
运行上述程序,得到结果是8,即字符串"ab"在字符串"abadcbbab"中出现的次数为8.
该算法的难点在于初始值的理解,即当i=0时,次数为1,若j=0时,则次数为0。还有就是子问题的转化,既要考虑A中前i-1个字符在B中前j-1个字符的子问题(A[i]=B[j]),无论什么哪种情况都需要考虑A中i个字符在B中j-1个字符中的子问题。