97 交错字符串

题目

给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。

两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:

s = s1 + s2 + … + sn
t = t1 + t2 + … + tm
|n - m| <= 1
交错 是 s1 + t1 + s2 + t2 + s3 + t3 + … 或者 t1 + s1 + t2 + s2 + t3 + s3 + …
注意:a + b 意味着字符串 a 和 b 连接。

示例 1:

输入:s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出:true
示例 2:

输入:s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出:false
示例 3:

输入:s1 = “”, s2 = “”, s3 = “”
输出:true

  • 方法一:二维动态规划
class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
    	//交错字符串,则s3全部是由s1和s2组成的,故他们的字符数一定是相等的,不相等则返回false
        if(s1.length()+s2.length()!=s3.length()) return false;
        //dp[i][j]表示s3的前i+j个元素,是否由s1的前i个元素和s2的前j个元素组成
        //i的取值范围是0~n,可以是前0个元素或前n个元素,故数组的行有n+1行
        vector<vector<bool>> dp(s1.length()+1,vector<bool>(s2.length()+1,false));
        
        dp[0][0]=true;//初始化前s3的0个元素匹配s1或s2,为true
        //初始化第一列,s3全是由s1匹配的。如果当前第i个元素匹配成功的话,看前i-1个元素是否匹配成功
        for(int i=1;i<=s1.size();i++)
            dp[i][0]= s3[i-1]==s1[i-1]&&dp[i-1][0];
        //初始化第一行,s3全是由s2匹配的。如果当前第j个元素匹配成功的话,看前j-1个元素是否匹配成功
        for(int j=1;j<=s2.size();j++)
            dp[0][j]= s3[j-1]==s2[j-1]&&dp[0][j-1];
        //dp[i][j]=(s1[i-1]==s3[i+j-1]&&dp[i-1][j])||(s2[j-1]==s3[i+j-1]&&dp[i][j-1])
        //或 表示当前第i+j-1个元素既可以匹配s1的第i个元素也可以匹配s2的第j个元素,二者满足一种情况即可
        for(int i=1;i<=s1.size();i++)
        {
            for(int j=1;j<=s2.size();j++)
                dp[i][j]= (s1[i-1]==s3[i+j-1]&&dp[i-1][j])||(s2[j-1]==s3[i+j-1]&&dp[i][j-1]);
        }
        return dp[s1.size()][s2.size()];//返回是否匹配了s1的前m个元素s2的前n个元素
    }
};
  • 时间复杂度O(n^2)

  • 空间复杂度O(n^2)

  • 思路

    • 交错字符串,s3全部是由s1和s2的所有字符组成的
    • dp[i][j]表示s3的前i+j个字符,是否由s1的前i个字符和s2的前j个字符组成。先初始化dp数组的边界,再根据递推公式填dp数组
    • 递推公式:dp[i][j]= (s1[i-1]==s3[i+j-1]&&dp[i-1][j])||(s2[j-1]==s3[i+j-1]&&dp[i][j-1])
    • 详细解释在代码注释
  • 法二:滚动数组实现一维动态规划

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
    	//如果s3的字符数不等于s1和s2的字符数之和,返回false
        if(s1.length()+s2.length()!=s3.length()) return false;
  		//一维dp数组
        vector<bool> f(s2.size()+1,false);
        f[0]=true;//初始化边界为true,s3的前0个字符与s1或s2匹配成功
		//初始化对应到二维dp中就是第一行,即s3全部匹配的是s2的字符
        for(int i=1;i<=s2.size();i++)
            f[i]=s2[i-1]==s3[i-1]&&f[i-1];
        //两层for循环,外层for对应二维数组中的列,内层for表示一行
        for(int i=1;i<=s1.size();i++)
        {
        	//先初始化当前行的第一个元素,判断s3的第i个元素是否和s1的第1个元素匹配,且s3的前i-1个元素是否匹配成功
        	//对应在二维数组中就是第一列的元素,即s3全部和s1进行匹配
            f[0]=s1[i-1]==s3[i-1]&&f[0];
            //填当前行的dp数组
            //当前位置的元素是否匹配成功只与它左边的元素和上边的元素有关
            //如果s3的第i+j个元素和s1的第i个元素匹配成功,则要判断s3是否已经把s1的前i-1个元素已经匹配完了,在一维数组中表示为尚未被改次循环修改的f[j]的值
            //如果s3的第i+j个元素和s2的第j个元素匹配成功,则要判断s3是否已经把s2的前j-1个元素已经匹配完了,在一维数组中表示为f[j-1]
            //s3的第i+j个字符只要成功匹配一个字符即可,故两种情况用 或 连接
            for(int j=1;j<=s2.size();j++)
                f[j]=(s1[i-1]==s3[i+j-1]&&f[j])||(s2[j-1]==s3[i+j-1]&&f[j-1]);
        }

        return f[s2.size()];
    }
};

  • 时间复杂度O(n^2)
  • 空间复杂度O(n)
  • 思路
    • 由于二维动态规划中,确定当前行的值时只用到当前行和上一行的值,且最后只需要最后一行最后一个元素的值,故可以采用滚动数组将其优化为一维动态规划
    • 详细解释见代码注释
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值