97. 交错字符串

97. 交错字符串

题目描述

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

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

  • s = s 1 + s 2 + . . . + s n s = s_1 + s_2 + ... + s_n s=s1+s2+...+sn
  • t = t 1 + t 2 + . . . + t m t = t_1 + t_2 + ... + t_m t=t1+t2+...+tm
  • ∣ n − m ∣ ≤ 1 |n - m| \le 1 nm1
  • 交错 是 s 1 + t 1 + s 2 + t 2 + s 3 + t 3 s_1 + t_1 + s_2 + t_2 + s_3 + t_3 s1+t1+s2+t2+s3+t3 + … 或者 t 1 + s 1 + t 2 + s 2 + t 3 + s 3 + . . . t_1 + s_1 + t_2 + s_2 + t_3 + s_3 + ... t1+s1+t2+s2+t3+s3+...

提示:a + b 意味着字符串 ab 连接。

示例 1:


输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出:true

示例 2:

输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
输出:false

示例 3:

输入:s1 = "", s2 = "", s3 = ""
输出:true

提示:

  • 0 ≤ s 1. l e n g t h , s 2. l e n g t h ≤ 100 0 \le s1.length, s2.length \le 100 0s1.length,s2.length100
  • 0 ≤ s 3. l e n g t h ≤ 200 0 \le s3.length \le 200 0s3.length200
  • s1s2、和 s3 都由小写英文字母组成

题解:

动态规划。

f[i][j] 表示 s1 的前 i 个字符和 s2 的前 j 个字符能否组成 s3 的前 i + j 个字符。

状态转移方程为:

  • s3[i + j] == s1[i], 则 f[i][j] |= f[i - 1][j]
  • s3[i + j] == s2[j], 则 f[i][j] |= f[i][j - 1]

时间复杂度: O ( n ∗ m ) O(n*m) O(nm)

额外空间复杂度: O ( n ∗ m ) O(n*m) O(nm)

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int n1 = s1.size();
        int n2 = s2.size();
        if ( n1 + n2 != s3.size() ) return false;
        vector<vector<bool>> f( n1 + 1, vector<bool>(n2 + 1) );
        f[0][0] = true;
        for ( int i = 0; i <= n1; ++i ) {
            for (int j = 0; j <= n2; ++j ) {
                if ( i && s3[i + j - 1] == s1[i - 1] ) {
                    f[i][j] = f[i - 1][j];
                }
                if ( j && s3[i + j - 1] == s2[j - 1] )
                    f[i][j] = f[i][j] | f[i][j - 1];
            }
        }
        return f[n1][n2];
    }
};
/*
时间:4ms,击败:78.25%
内存:6.3MB,击败:94.34%
*/

可以发现, f[i][j] 只和 f[i - 1][j]f[i][j - 1] 有关,可以使用滚动数组优化:

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int n1 = s1.size();
        int n2 = s2.size();
        if ( n1 + n2 != s3.size() ) return false;
        vector<bool> f(n2 + 1);
        f[0] = true;
        for ( int i = 0; i <= n1; ++i ) {
            for (int j = 0; j <= n2; ++j ) {
                if ( i ) f[j] = f[j] & (s3[i + j - 1] == s1[i - 1]);
                if ( j ) f[j] = f[j] | (f[j - 1] && s3[i + j - 1] == s2[j - 1]);
            }
        }
        return f[n2];
    }
};
/*
时间:0ms,击败:100.00%
内存:6.1MB,击败:97.88%
*/
这是一道比较有意思的字符串题目,我们可以使用动态规划来解决。使用 Kotlin 语言来实现,具体思路如下: 定义一个二维布尔数组 `dp[i][j]`,表示 s1 的前 i 个字符和 s2 的前 j 个字符能否交错组成 s3 的前 i+j 个字符。 初始状态:当 s1 和 s2 都为空时,s3 也为空,因此 `dp[0][0] = true`。 状态转移:对于每个 `dp[i][j]`,我们有两种选择: - 如果 `s1[i-1] == s3[i+j-1]`,则可以使用 `s1[i-1]` 来匹配 `s3[i+j-1]`,此时需要判断 `dp[i-1][j]` 是否为 true。 - 如果 `s2[j-1] == s3[i+j-1]`,则可以使用 `s2[j-1]` 来匹配 `s3[i+j-1]`,此时需要判断 `dp[i][j-1]` 是否为 true。 最终的结果为 `dp[s1.length][s2.length]`。 完整的代码如下: ```kotlin fun isInterleave(s1: String, s2: String, s3: String): Boolean { if (s1.length + s2.length != s3.length) { return false } val dp = Array(s1.length + 1) { BooleanArray(s2.length + 1) } // 初始化状态 dp[0][0] = true // 初始化第一行 for (j in 1..s2.length) { dp[0][j] = dp[0][j-1] && s2[j-1] == s3[j-1] } // 初始化第一列 for (i in 1..s1.length) { dp[i][0] = dp[i-1][0] && s1[i-1] == s3[i-1] } // 状态转移 for (i in 1..s1.length) { for (j in 1..s2.length) { dp[i][j] = (dp[i-1][j] && s1[i-1] == s3[i+j-1]) || (dp[i][j-1] && s2[j-1] == s3[i+j-1]) } } return dp[s1.length][s2.length] } ``` 我们可以使用以下代码测试这个函数: ```kotlin fun main() { val s1 = "aabcc" val s2 = "dbbca" val s3 = "aadbbcbcac" val res = isInterleave(s1, s2, s3) println(res) } ``` 输出结果为: ``` true ``` 这说明我们的代码已经正确地判断了 s3 是否是由 s1 和 s2 交错组成的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值