DP刷题练习(五)

DP刷题练习(五)

文章内容学习自代码随想录,感谢carl!!!!

文章目录

  • DP刷题练习(五)
      • [115. 不同的子序列 - 力扣(LeetCode)](https://leetcode.cn/problems/distinct-subsequences/)
      • [583. 两个字符串的删除操作 - 力扣(LeetCode)](https://leetcode.cn/problems/delete-operation-for-two-strings/description/)
      • [72. 编辑距离 - 力扣(LeetCode)](https://leetcode.cn/problems/edit-distance/)
      • [647. 回文子串 - 力扣(LeetCode)](https://leetcode.cn/problems/palindromic-substrings/)
      • [516. 最长回文子序列 - 力扣(LeetCode)](https://leetcode.cn/problems/longest-palindromic-subsequence/)

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];
    }

你可能感兴趣的:(写写算法,算法,数据结构,蓝桥杯)