leetcode#87 扰乱字符串

leetcode#87 扰乱字符串

题目:

使用下面描述的算法可以扰乱字符串 s 得到字符串 t :
1、如果字符串的长度为 1 ,算法停止
2、如果字符串的长度 > 1 ,执行下述步骤:

  • 在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符串 x 和 y ,且满足 s = x + y 。
  • 随机 决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s 可能是 s = x + y 或者 s = y + x 。
  • 在 x 和 y 这两个子字符串上继续从步骤 1 开始递归执行此算法。
    给你两个 长度相等 的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。如果是,返回 true ;否则,返回 false 。
示例:
输入:s1 = "great", s2 = "rgeat"
输出:true
解释:s1 上可能发生的一种情形是:
"great" --> "gr/eat" // 在一个随机下标处分割得到两个子字符串
"gr/eat" --> "gr/eat" // 随机决定:「保持这两个子字符串的顺序不变」
"gr/eat" --> "g/r / e/at" // 在子字符串上递归执行此算法。两个子字符串分别在随机下标处进行一轮分割
"g/r / e/at" --> "r/g / e/at" // 随机决定:第一组「交换两个子字符串」,第二组「保持这两个子字符串的顺序不变」
"r/g / e/at" --> "r/g / e/ a/t" // 继续递归执行此算法,将 "at" 分割得到 "a/t"
"r/g / e/ a/t" --> "r/g / e/ a/t" // 随机决定:「保持这两个子字符串的顺序不变」
算法终止,结果字符串和 s2 相同,都是 "rgeat"
这是一种能够扰乱 s1 得到 s2 的情形,可以认为 s2 是 s1 的扰乱字符串,返回 true

思路:

1、记忆化搜索

枚举分割点,用hashmap记录。

2、区间dp

对一个字符串进行分割,形成两个子问题,那就是交换和不交换。对于一个字符串i~j,分割点为k,有

  • 交换:取决于更小的子问题,也就是交换的两部分是否对应为扰乱字符串,a[i ~ k] == b[k ~ j]&&a[k ~ j] == b[i ~ k],这里的等于指的是否相互为扰乱字符串。
  • 不交换:取决于更小的子问题,也就是交换的两部分是否对应为扰乱字符串,a[i ~ k] == b[i ~ k]&&a[k ~ j] == b[k ~ j],这里的等于指的是否相互为扰乱字符串。

因此,每一个问题都由这两个子问题决定,那么我们就可以定义一个dp数组了,dp既要有区间长度,也要包括分割点,所以我们定义dp[i][j][len] 代表 s1 从 i开始,s2从 j 开始,后面长度为 len 的字符是否能形成「扰乱字符串」(互为翻转)。 然后枚举i,j每个起点和len长度,最后枚举分割点即可。
dp数组初始化,长度为一时,是否为扰乱字符串仅取决于两个字符是否相等,以此初始化len为1的起始情况。

代码:

class Solution
{
public:
    bool isScramble(string s1, string s2)
    {
        int m = s1.length(), n = s2.length();
        if (m != n)
            return false;
        bool dp[m][m][m + 1];
        memset(dp, false, sizeof(dp));
        for (int i = 0; i < m; ++i)
            for (int j = 0; j < n; ++j)
                dp[i][j][1] = (s1[i] == s2[j]);
        for (int r = 2; r <= m; ++r)
            for (int i = 0; i + r - 1 < m; ++i)
                for (int j = 0; j + r - 1 < m; ++j)
                    for (int len = 1; len < r; ++len)
                    {
                        bool a = dp[i][j][len] && dp[i + len][j + len][r - len];
                        bool b = dp[i][j + r - len][len] && dp[i + len][j][r - len];
                        if(a||b)
                        dp[i][j][r] = true;
                    }
        return dp[0][0][m];
    }
};

你可能感兴趣的:(leetcode,数据结构,字符串,算法,leetcode)