[LeetCode P97] Interleaving String动态规划

原题:

Given s1, s2, s3, 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.

解题思路:
首先想到用递归去做,我们每次吃掉s3中的一个字符,如果s1中开头的字符是这个字符,我们就用s1的开头字符去匹配,如果s2的开头字符是这个字符,就用s2去匹配,最后有两种可能的子问题。
代码非常简单:

if (s3.length() == 0) return s1 == "" && s2 == "";
return (s1.length() && s1[0] == s3[0] && isInterleave(s1.substr(1), s2, s3.substr(1)))|| (s2.length() && s2[0] == s3[0] && isInterleave(s1, s2.substr(1), s3.substr(1)));

但是这样做时间复杂度太高,最差的情况下,有2^n。
所以我们考虑用DP,因为上述问题中有很多子问题是重复的。
我们的DP数组保存的应该是:长度为j的s1子字符串与长度为m的s2子字符串是否能够Interleaving形成长度为j+m的s3子字符串(都是从头开始数的)。
状态转移方程应该是:
dp[j+1][m] = dp[j][m] && s1[j] == s3[j+m+1]
dp[j][m+1]同理可得。
最后的代码:

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        if(s1.length() + s2.length() != s3.length()) return false;
        vector<vector<bool>> dp(s1.length()+1, vector<bool>(s2.length()+1, false));
        dp[0][0] = true;
        for (int i = 1; i <= s3.length(); ++i)
        {
            // 长度为j的s1子串 + 长度为i-j的s2子串
            for (int j = max(int(i - s2.length()), 0); j <= min(int(s1.length()), i); ++j)
            {
                int m = i - j;
                dp[j][m] = (j > 0 && dp[j-1][m] && s1[j-1] == s3[i-1]) 
                            || (m > 0 && dp[j][m-1] && s2[m-1] == s3[i-1]);
            }
        }
        return dp[s1.length()][s2.length()];
    }
};

你可能感兴趣的:(LeetCode,leetcode)