1->一个三角形数组,找出从顶到底的最短路径
解题方法:从三角形的倒数第2行开始,状态转移方程f[i][j]=min(f[i][j+1],f[i+1][j+1])+(i,j);
int minmumTotal(vector<vector<int> >& triangle){
for(int i=trangle.size()-2;i>=0;i--){
for(int j=0;j<i+1;j++)
triangle[i][j]+=min(triangle[i+1][j],triangle[i+1][j+1]);
}
return triangle[0][0];
}
2->回文子串的最小分割
解题方法:求出所有的回文子串,采用深度搜索的方法,中间注意分割和不分割之间的区别
那么求回文子串的最小分割数,则可以采用动态规划的方法。状态转移方程f(i)=min{f(j+1)+1},i<=j<n
int minCut(string s){
const int n=s.size();
int f[n+1]; bool p[n][n];
fill_n(&p[0][0],n*n,false);
for(int i=0;i<=n;i++) f[i]=n-1-i;
for(int i=n-1;i>=0;i--){
for(int j=i;j<n;j++){
if(s[i]==s[j] &&(j-i<2 || p[i+1][j-1])){ p[i][j]=true; f[i]=min(f[i],f[j+1]+1;)}
}
}
}
return f[0];
}
3->判断一个字符串是否是两个字符串的组
解题方法:设状态f[i][j] 表示s1[0.i]和s2[0,j],匹配s3[0,i+j].如果s1的最后等于一个字符s3的最后一个字符,那么f[i][j]=f[i-1][j]。若s2的最后一个字符等于s3的最后一个字符,那么f[i][j]=f[i][j-1]
bool isInterleave(string s1,string s2,string s3){
if(s2.length()+s1.length()!=s3.length()) return false;
bool f[s1.length()+1][s2.length()+1];
for(int i=1;i<s1.length()+1;i++) f[i][0]=f[i-1][0]&&s1[i-1]==s3[i-1];
for(int i=1;i<s2.length()+1;i++) f[0][i]=f[0][i-1] &&s2[i-1]==s3[i-1];
for(int i=1;i<=s1.length();i++)
for(int j=1;j<=s2.length();j++)
f[i][j]=(s1[i-1]==s3[i+j-1]&&f[i-1][j]) || (s2[j-1]==s3[i+j-1] &&f[i][j-1]);
return f[s1.length()][s2.length()];
}
4->判断两个字符串是否互为scramble
bool isScramble(string s1,string s2){
const int N=s1.size();
if(N!=s2.size()) return false;
bool f[N+1][N][N]; //表示长度为n,起点为s1[i]和起点为s2的字符串是否互为scramble
fill_n(&f[0][0][0],(N+1)*N*N,false);
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
f[1][i][j]=(s1[i]==s2[j]);
for(int n=1;n<=N;++n)
for(int i=0;i+n<=N;i++){
for(int j=0;j+n<=N;j++)
for(int k=1;k<n;k++){
if(f[k][i][j]&& f[n-k][o+k][j-k] ||f[k][i][j+n-k]&& f[n-k][i+k][j]){f[n][i][j]=true; break;}
}
}
return f[N][0][0];
}
5->一个n*m矩阵从起点到终点的最短路径
动态规划的解题方法:
int minPathSum(vector<vector<int> > &grid){
const int m=grid.size();
const int n=grid[0].size();
int f[m][n];
f[0][0]=grid[0][0];
for(int i=1;i<m;i++)
f[i][0]=f[i-1][0]+grid[i][0];
for(int i=1;i<n;i++)
f[0][i]=f[0][i-1]+grid[0][i];
for(int i=1;i<m;i++)
for(int j=1;j<m;j++) f[i][j]=min(f[i-1][j],f[i][j-1])+grid[i][j];
return f[m-1][n-1];
}
6->编辑距离问题
状态式:f[i][j],表示A[0,i]和B[0,j]之间的最小编辑距离。当字符c==d时,f[i][j]=f[i-1][j-1],当字符c!=d时,有三种情况c替换d 。f[i][j]=f[i-1][j-1]+1,当在c后面添加一个d.f[i][j]=f[i][j-1]+1.当要删除c时,f[i][j]=f[i-1][j]+1;
int minDistance(const string &word1,const string &word2){
const int n=word1.size(); const int m=word2.word2.size();
int f[n+1][m+1];
for(int i=0;i<=n;i++) f[i][0]=i;
for(int j=0;j<=m;j++) f[0][j]=j;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(word1[i-1]==word2[j-1]) f[i][j]=f[i-1][j-1];
else
int mn=min(f[i-1][j],f[i][j-1]); f[i][j]=1+min(f[i-1][j-1],mn)+1;
}
return f[n][m];
}
7->Decode ways
int numDecodings(const string &s){
if(s.empty() || s[0]=='0') return 0;
int prev=0; int cur=1;
for(int i=1;i<=s.szie();i++){
if(s[i-1]=='0') cur=0;
if(i<2 || !(s[i-2]=='1' || (s[i-2]=='2' && s[i-1]<='6'))) prev;
int tmp=cur; cur=prev+cur;
prev=cur;
}
return cur;
}
8->Distinct Subsequences
int numDistinct(const string &s,const string &t){
vector<int> f(t.size()+1);
f[0]=1;
for(int i=0;i<s.size();i++){
for(int j=t.size()-1;j>=0;j--) f[j+1]+=s[i]==t[j]?f[j]:0;
}
return f[t.size()];
}
9->w Break
bool wordBreak(string s,set<string> &dict){
vector<bool> f(s.size()+1,false);
f[0]=true;
for(int i=1;i<=s.size();i++){
for(int j=i-1;j>=0;j--)
if(f[j] && dict.find(s.substr(j,i-j))!=dict.end()){ f[i]=true; break;}
}
return f[s.size()];
}