如有缺漏谬误,还请批评指正。
1.不同路径
两种转移方式:从上到下/从左到右。
下标从1开始,f[1][1]初始化为1,循环里需特判跳过f[1][1]的计算。
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> f(m+1,vector<int>(n+1));
f[1][1]=1;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(i==1&&j==1) continue;
f[i][j]=(f[i-1][j]+f[i][j-1]);
}
}
return f[m][n];
}
};
2.最小路径和
求最小值,状态转移数组需初始化为一个较大值。
(1)下标从0开始
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m=grid.size();
int n=grid[0].size();
vector<vector<int>> f(m,vector<int>(n,500000));
f[0][0]=grid[0][0];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0&&j==0) continue;
if(i&&j) f[i][j]=min(f[i-1][j],f[i][j-1])+grid[i][j];
else if(i) f[i][j]=f[i-1][j]+grid[i][j];
else if(j) f[i][j]=f[i][j-1]+grid[i][j];
}
}
return f[m-1][n-1];
}
};
(2)下标从1开始
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m=grid.size();
int n=grid[0].size();
vector<vector<int>> f(m+1,vector<int>(n+1,500000));
f[1][1]=grid[0][0];
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(i==1&&j==1) continue;
if(i&&j) f[i][j]=min(f[i-1][j],f[i][j-1])+grid[i-1][j-1];
else if(i) f[i][j]=f[i-1][j]+grid[i-1][j-1];
else if(j) f[i][j]=f[i][j-1]+grid[i-1][j-1];
}
}
return f[m][n];
}
};
3.最长回文子串
下标i遍历左边界,下标j遍历右边界,如果左右边界字符相同,当前最大回文子串长度+1。
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
if(n<2) return s;
int maxv=1,st=0;
vector<vector<bool>> f(n,vector<bool>(n,false));
for(int i=0;i<n;i++) f[i][i]=true; //所有长度为1的子串都是回文串
//枚举子串长度
for(int len=2;len<=n;len++){
//枚举子串左边界
for(int i=0;i<=n-len;i++){
int j=i+len-1; //子串右边界
if(s[i]==s[j]&&(len==2||f[i+1][j-1])){
f[i][j]=true; //s[i...j]是回文串
if(len>maxv){
maxv=len; //更新最大回文子串长度
st=i; //更新最大回文子串起始位置
}
}
}
}
return s.substr(st,maxv);
}
};
4.最长公共子序列
f[i][j]表示到A[i]和B[j]为止的最长公共子序列长度。
状态转移依据“当前字符是否一致”:
- 一致:最长公共子序列长度+1
- 不一致:f[i][j]=max(f[i-1][j],f[i][j-1]); 取两者间最大值。
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int n=text1.size(),m=text2.size();
vector<vector<int>> f(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(text1[i-1]==text2[j-1]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
}
}
return f[n][m];
}
};
5.编辑距离
f[i][j]
表示将字符串 A[0..i-1]
转换成 B[0..j-1]
所需的最少操作次数。
三种编辑方式:增、删、改。
- 增:f[i][j-1]+1 (在A的末尾插入B[j-1])
- 删:f[i-1][j]+1 (删除A[i-1])
- 改:f[i-1][j-1]+1 (替换A[i-1]为B[j-1])
class Solution {
public:
int minDistance(string word1, string word2) {
int m=word1.size();
int n=word2.size();
vector<vector<int>> f(m+1,vector<int>(n+1,INT_MAX));
for(int i=0;i<=m;i++) f[i][0]=i;
for(int j=0;j<=n;j++) f[0][j]=j;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(word1[i-1]==word2[j-1]) f[i][j]=f[i-1][j-1];
else{
f[i][j]=min(f[i-1][j],f[i][j-1])+1;
f[i][j]=min(f[i][j],f[i-1][j-1]+1);
}
}
}
return f[m][n];
}
};