DP刷题练习(五)
文章内容学习自代码随想录,感谢carl!!!!
[TOC]
115. 不同的子序列 - 力扣(LeetCode)
居然连long long 也要爆,无奈unsigned long long
//dp定义:
unsigned long long dp[n+1][m+1];//以i-1作为结尾的字符串s中
//有dp[i][j]个以j-1作为结尾字符串t
//递推公式:
//注意求的是s里面有多少个t
if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
//s[i-1]==t[j-1],那么如果你要使用这个s[i-1]==t[j-1],那你的数量就是继承之前的dp[i-1][j-1]
//但是你也可以不用这个s[i-1]去和t匹配,那就是dp[i-1][j]
else dp[i][j]=dp[i-1][j];
//没用s[i-1]可以用
//初始化:
for(int i=1;i<=n;i++) dp[i][0]=1;//子串是空字符串
for(int j=1;j<=m;j++) dp[0][j]=0;//母串是空字符串
dp[0][0]=1;//都是空字符串
int numDistinct(string s, string t) {
int n=s.size();int m=t.size();
unsigned long long dp[n+1][m+1];//以i-1作为结尾的字符串s中
//有dp[i][j]个以j-1作为结尾字符串t
for(int i=1;i<=n;i++) dp[i][0]=1;
for(int j=1;j<=m;j++) dp[0][j]=0;
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
else dp[i][j]=dp[i-1][j];
}
}
return dp[n][m];
}
583. 两个字符串的删除操作 - 力扣(LeetCode)
找两个字符串最长的公共子序列,然后分别删掉那些无法让其变成相同的字串字符即可
int minDistance(string word1, string word2) {
int n=word1.size();int m=word2.size();
int dp[n+1][m+1];//表示以i-1结尾的字串,j-1结尾的字串二者最长的公共子序列是dp[i][j]
int cnt=0;
int ans=0;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(word1[i-1]==word2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
cnt=max(cnt,dp[i][j]);
}
}
ans=n+m-2*cnt;
return ans;
}
另解:
int minDistance(string word1, string word2) {
int n=word1.size();int m=word2.size();
int dp[n+1][m+1];
/*使i-1为尾word1,以j-1为尾的word2,为相同字符串的最小
操作次数为dp[i][j]
*/
for(int i=1;i<=n;i++) dp[i][0]=i;//和空串比那就有把i删干净
for(int j=1;j<=m;j++) dp[0][j]=j;//同理
dp[0][0]=0;//两个空串不用删
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(word1[i-1]==word2[j-1]) dp[i][j]=dp[i-1][j-1];//这两个相同不用管
else dp[i][j]=min(dp[i-1][j]+1,min(dp[i][j-1]+1,dp[i-1][j-1]+2));
} //删i-1加一次次数,删j-1加一次次数,两个都删加两次次数
}
return dp[n][m];
}
72. 编辑距离 - 力扣(LeetCode)
int dp[n+1][m+1];
/*以i-1为结尾的word1转换成以j-1为结尾的word2使用的最少操作次数为dp[i][j]*/
int minDistance(string word1, string word2) {
int n=word1.size();int m=word2.size();
int dp[n+1][m+1];
dp[0][0]=0;
for(int i=1;i<=n;i++) dp[i][0]=i;
for(int j=1;j<=m;j++) dp[0][j]=j;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(word1[i-1]==word2[j-1]) dp[i][j]=dp[i-1][j-1];//这个位置相同不做操作
else dp[i][j]=min(dp[i-1][j-1]+1,min(dp[i-1][j]+1,dp[i][j-1]+1));
}//这个位置不同,可以转化其中一个,也可以把这个位置删掉
}
return dp[n][m];
}
647. 回文子串 - 力扣(LeetCode)
int countSubstrings(string s) {
int n=s.size();
int ans=0;
bool dp[n][n];//[i,j]的字串是否回文是dp[i][j];
memset(dp,false,sizeof(dp));
for(int i=n-1;i>=0;i--)
{
for(int j=i;j<=n-1;j++)
{
if(s[i]==s[j]){
if(j-i<=1) {
dp[i][j]=true;}
else dp[i][j]=dp[i+1][j-1];
}
if(dp[i][j]) ans++;
}
}
return ans;
}
516. 最长回文子序列 - 力扣(LeetCode)
int longestPalindromeSubseq(string s) {
int n=s.size();
int dp[n][n];//[i,j]间最长回文子序列的长度
memset(dp,0,sizeof(dp));
for(int i=0;i<=n-1;i++) dp[i][i]=1;
for(int i=n-1;i>=0;i--){
for(int j=i+1;j<=n-1;j++){
if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]+2;
else dp[i][j]=max(dp[i][j-1],dp[i+1][j]);
}
}
return dp[0][n-1];
}