使用动态规划求解字符串问题

72Edit Distance–字符串编辑问题

问题描述:

Given two words 
word1
 and 
word2
, find the minimum number of steps required to convert 
word1
 to 
word2
. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

a) Insert a character
b) Delete a character
c) Replace a character

问题解析:

1. 本题是求两个字符串s1和s2,编辑s1让其变为s2。可以在s1中插入字符操作、删除字符操作、替换字符操作,每次操作增加步骤1次,求s1变为s2的最小步骤数。
2. 解决此类问题经典解法就是用动态规划。
       (1)s1大小为size1,s2大小为size2。定义一个size1+1*size2+1的dp,其中dp[i][j]表示s1的前i的字符变为和s2的前j个字符所需要的最小步骤数。
       (2)dp[i][j]的值应该是:当s1[i]==s2[j]时,dp[i][j]==dp[i-1][j-1];当s[i] != s[j]时,dp[i][j] = dp[i-1][j]+1(删除一个字符)、dp[i][j] = dp[i][j-1] + 1(添加一个字符)、dp[i][j] = dp[i-1][j-1] + 1(替换一个字符)。选择三者步骤数最少的一个。

代码如下:

class Solution {
public:
    // 使用动态规划来解决此问题,创建dp,dp[i][j]表示word1的i个字符转化为word2的前j个字符所需要的花费
    int minDistance(string word1, string word2) 
    {
        int m = (int)word1.size();
        int n = (int)word2.size();
        
        // 创建dp
        vector<vector<int>>dp(m+1, vector<int>(n+1, 0));
        // 初始化第一行,代表word1为空时转化为word2
        for(int j=1; j<=n; ++j)
            dp[0][j] = dp[0][j-1] + 1;
        // 初始化第一列,代表word2为空时转化为word1
        for(int i=1; i<=m; ++i)
            dp[i][0] = dp[i-1][0] + 1;
        for(int i=1; i<=m; ++i)
        {
            for(int j=1; j<=n; ++j)
            {
                // dp[i-1][j]表示word1前i-1转换为word2前j个,需要花费,删掉1个就是前i和前j
                // dp[i][j-1]表示word1前i转换为word2前j-1个,需要花费,添加1个就是前i和前j
                // dp[i-1][j-1]表示word1前i-1转换为word2前j-1个需要花费。word1[i]==word2[j],则不需要花费就是前i和前j.否则需要替换多花费1
                int z;
                dp[i][j] = dp[i-1][j] < dp[i][j-1] ? dp[i-1][j]+1 : dp[i][j-1]+1;
                z = (word1[i-1] == word2[j-1] ? dp[i-1][j-1] : dp[i-1][j-1]+1);
                dp[i][j] = dp[i][j] < z ? dp[i][j] : z;
                
            }
        }
        return dp[m][n]; 
    }
};

115Distinct Subsequences—求字符串S中有几个字符串t

问题描述:

Given a string S and a string T, count the number of distinct subsequences of S which equals T.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Here is an example:
S = "rabbbit"T = "rabbit"

Return 3.

问题解析:

1. 此题是求一个字符串S中有几个字符串t。可以转化为上题,只是通过在字符串S中删除字符来变为字符串t,看有几种解法。
2. 解决此类问题经典解法就是用动态规划。
       (1)s大小为size1,t大小为size2。定义一个size1*size2的dp,其中dp[i][j]表示s1的前i+1的字符变为和s2的前j+1个字符的方法数。
       (2)dp[i][j]的值应该是:当s1[i]==s2[j]时,dp[i][j]==dp[i-1][j] + dp[i-1][j-1],表示的是使用当前这个字符和不要s中当前这个字符总共方法数;当s[i] != s[j]时,dp[i][j] = dp[i-1][j],s中当前这个字符一定用不上,所以表示不用当前这个字符的方法数。

代码如下:

class Solution {
public:
    // 利用动态规划来做
    int numDistinct(string s, string t) 
    {
        if(s.empty())
            return 0;
        if(t.empty())
            return 1;
        int ssize = s.size();
        int tsize = t.size();
        vector<vector<int>> dp(ssize, vector<int>(tsize, 0));
        // 填写第一行
        if(s[0] ==t[0])
            dp[0][0]=1;
        // 填写第一列
        for(int i=1; i<ssize; ++i)
        {
            if(t[0] ==s[i])
                dp[i][0] = 1+ dp[i-1][0];
            else
                dp[i][0] = dp[i-1][0];
        }
        // 填写剩余的dp
        for(int i=1; i<ssize; ++i)
        {
            for(int j=1; j<tsize; ++j)
            {
                if(s[i] == t[j])
                    dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
                else
                    dp[i][j] = dp[i-1][j];     
            }
        }
        return dp[ssize-1][tsize-1];
    }
};

115

Distinct Subsequences

    原文作者:动态规划
    原文地址: https://blog.csdn.net/baidu_33604078/article/details/79000179
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞