动态规划题解

1. Leetcode 96:给定一个数字,输出从1至该数所能构成的BST(二叉搜索树)

class Solution {
public:
    int numTrees(int n) {
        if(n==0||n==1)
            return n;
        vector<int> ans;
        ans.push_back(1);
        ans.push_back(1);
        for(int i=2;i<=n;++i)
        {
            int tempsum = 0;
            for(int j=0;j<=i-1;++j)
            {
                tempsum += ans[j]*ans[i-1-j];
            }
            ans.push_back(tempsum);
        }
        return ans.back();
    }

};

2.Leetcode 97:

Interleaving String

Given s1s2s3, find whether s3 is formed by the interleaving of s1 and s2.

For example,
Given:
s1 = "aabcc",
s2 = "dbbca",

When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.

 

可以用递归做,每匹配s1或者s2中任意一个就递归下去。但是会超时。

因此考虑用动态规划做。

s1, s2只有两个字符串,因此可以展平为一个二维地图,判断是否能从左上角走到右下角。

当s1到达第i个元素,s2到达第j个元素:

地图上往右一步就是s2[j-1]匹配s3[i+j-1]。

地图上往下一步就是s1[i-1]匹配s3[i+j-1]。

示例:s1="aa",s2="ab",s3="aaba"。标1的为可行。最终返回右下角。

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int len1 = s1.size(), len2 = s2.size(), len3 = s3.size();
    if (len1 + len2 != len3)
    return false;
    vector<vector<bool>> path(len1 + 1, vector<bool>(len2 + 1,false));
    for (int i = 0; i <= len1; ++i)
    {
    for (int j = 0; j <= len2; ++j)
    {
    if (i == 0 && j == 0)
    {
    path[i][j] = true;
    }
    else if (i == 0)
    {
    path[i][j] = path[i][j-1]&(s3[j - 1] == s2[j - 1]);
    }
    else if (j == 0)
    {
    path[i][j] = path[i-1][j]&(s3[i - 1] == s1[i - 1]);
    }
    else
    {
    path[i][j] = (path[i][j-1]&(s3[i+j-1]==s2[j-1]))||(path[i-1][j]&(s3[i+j-1]==s1[i-1]));
    }
    }
    }
    return path[len1][len2];
    }

};

3. LeetCode 115:

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

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.

 

看到有关字符串的子序列或者配准类的问题,首先应该考虑的就是用动态规划Dynamic Programming来求解,这个应成为条件反射。而所有DP问题的核心就是找出递推公式,想这道题就是递推一个二维的dp数组,下面我们从题目中给的例子来分析,这个二维dp数组应为:

复制代码
  Ø r a b b b i t
Ø 1 1 1 1 1 1 1 1
r 0 1 1 1 1 1 1 1
a 0 0 1 1 1 1 1 1
b 0 0 0 1 2 3 3 3
b 0 0 0 0 1 3 3 3
i 0 0 0 0 0 0 3 3
t 0 0 0 0 0 0 0 3 
复制代码

首先,若原字符串和子序列都为空时,返回1,因为空串也是空串的一个子序列。若原字符串不为空,而子序列为空,也返回1,因为空串也是任意字符串的一个子序列。而当原字符串为空,子序列不为空时,返回0,因为非空字符串不能当空字符串的子序列。理清这些,二维数组dp的边缘便可以初始化了,下面只要找出递推式,就可以更新整个dp数组了。我们通过观察上面的二维数组可以发现,当更新到dp[i][j]时,dp[i][j] >= dp[i][j - 1] 总是成立,再进一步观察发现,当 T[i - 1] == S[j - 1] 时,dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1],若不等, dp[i][j] = dp[i][j - 1],所以,综合以上,递推式为:

dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0)

代码:

static int x = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    return 0;
}();
class Solution {
public:
    int numDistinct(string s, string t) {
        int lens = s.size();
        int lent = t.size();
        vector<vector<int>> method(lent+1,vector<int>(lens+1,0)); //初始化
        for(int i=0;i<=lens;++i)
        {
            method[0][i] = 1;
        }
        for(int i=1;i<=lent;++i)
        {
            method[i][0] = 0;
        }
        for(int i=1;i<=lent;++i)
        {
            for(int j=1;j<=lens;++j)
            {
                if(t[i-1]!=s[j-1])
                {
                    method[i][j] = method[i][j-1];
                }
                else
                {
                    method[i][j] = method[i][j-1]+method[i-1][j-1];
                }
            }
        }
        return method[lent][lens];
    }

};

4. LeetCode 132 Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

Example:

Input: "aab"
Output: 1
Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.

代码:

// static int x = []()
// {
//     std::ios::sync_with_stdio(false);
//     cin.tie(NULL);
//     return 0;
// }();
class Solution {
public:
    int minCut(string s) {
        vector<vector<int>>dp(s.size(),vector<int>(s.size(),0));
        vector<int>palin(s.size()+1,0);
        for(int i=s.size()-1;i>=0;--i)
        {
            palin[i] = INT_MAX;
            for(int j=i;j<s.size();++j)
            {
                if(s[i]==s[j]&&(j-i<=1||1==dp[i+1][j-1]))
                {
                    dp[i][j] = 1;
                    palin[i] = min(1+palin[j+1],palin[i]);
                } 
            }
        }
        return palin[0]-1;
    }
};

猜你喜欢

转载自blog.csdn.net/qianli2333/article/details/80757303