Scramble String leetcode

题目链接

递归解法:s2[0...j]是否可以由s1[0...i]转换 isScramble(s2[0...j], s1[0...i]),可以分解成 i 个子问题(i 其实等于j,因为两个字符串长度不一样,肯定不能互相转换):

( isScramble(s2[0...k], s1[0...k]) &&  isScramble(s2[k+1...j], s1[k+1...i]) ) || ( isScramble(s2[0...k], s1[i-k...i]) &&  isScramble(s2[k+1...j], s1[0...i-k-1]) ),(k = 0,1,2 ... i-1,k相当于字符串的分割点)

只要一个子问题返回ture,那么就表示两个字符串可以转换。代码如下:

class Solution {
public:
    bool isScramble(string s1, string s2) {
        return isScrambleRecur(s1,s2);
    }
    bool isScrambleRecur(string &s1, string &s2)
    {
        string s1cop = s1, s2cop = s2;
        sort(s1cop.begin(), s1cop.end());
        sort(s2cop.begin(), s2cop.end());
        if(s1cop != s2cop)return false;//两个字符串所含字母不同
        if(s1 == s2)return true;
        
        int len = s1.size();
        for(int i = 1; i < len; i++)//分割位置
        {
            string s1left = s1.substr(0, i);
            string s1right = s1.substr(i);
            string s2left = s2.substr(0, i);
            string s2right = s2.substr(i);
            if(isScrambleRecur(s1left, s2left) && isScrambleRecur(s1right, s2right))
                return true;
            s2left = s2.substr(0, len-i);
            s2right = s2.substr(len-i);
            if(isScrambleRecur(s1left, s2right) && isScrambleRecur(s1right, s2left))
                return true;
        }
        return false;
    }
};

动态规划解法

递归解法有很多重复子问题,比如s2 = rgeat, s1 = great 当我们选择分割点为0时,要解决子问题 isScramble(reat, geat),再对该子问题选择分割点0时,要解决子问题 isScramble(eat,eat);而当我们第一步选择1作为分割点时,也要解决子问题 isScramble(eat,eat)。相同的子问题isScramble(eat,eat)就要解决2次。

动态规划用数组来保存子问题,设dp[k][i][j]表示s2从j开始长度为k的子串是否可以由s1从i开始长度为k的子串转换而成,那么动态规划方程如下

  1.    初始条件:dp[1][i][j] = (s1[i] == s2[j] ? true : false)
  2.    dp[k][i][j] = ( dp[divlen][i][j] && dp[k-divlen][i+divlen][j+divlen] )  ||  ( dp[divlen][i][j+k-divlen] && dp[k-divlen][i+divlen][j] ) (divlen = 1,2,3...k-1, 它表示子串分割点到子串起始端的距离) ,只要一个子问题返回真,就可以停止计算

代码如下:

class Solution {
public:
    bool isScramble(string s1, string s2) {
        if(s1.size() != s2.size())
            return false;
        const int len = s1.size();
        bool dp[len+1][len][len];
        for(int i=0;i<len;i++) {
            for(int j=0;j<len;j++) {
                dp[1][i][j] = (s1[i] == s2[j]) ? true:false;
            }
        }
        for(int k=2;k<=len;k++) {
            for(int i=0;i<=len-k;i++) {
                for(int j=0;j<=len-k;j++) {
                    dp[k][i][j] = false;
                    for(int div = 1;div<k && !dp[k][i][j];div++) {
                        dp[k][i][j] = (dp[div][i][j] && dp[k-div][i+div][j+div]) || (dp[div][i][j+k-div] && dp[k-div][i+div][j]);
                    }
                }
            }
        }
        return dp[len][0][0];
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值