【LeetCode】97.交错字符串

84 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

题目

给定三个字符串 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

img

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

示例 2

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

示例 3

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

提示

  • 0 <= s1.length, s2.length <= 100
  • 0 <= s3.length <= 200
  • s1s2、和 s3 都由小写英文字母组成

题解

思路

我们可以直接使用动态规划尝试填充 s3,常见的思路为使用二维数组 bool[len1][len2] dp; 其中dp[i][j]表示 s1 的前 i 个字符和 s2 的前 i 个字符是否可以交错组成 s3 的前 i+j 个字符 该方法需要注意的两个点为:

dp[0][0]一定为 true,因为 0 个字符和 0 个字符一起组成 s3 的前 0 个字符,一定是 true 的 需要首先初始化一下 dp[0][j],因为有可能出现 s1 为空字符的情况 状态转移方程为: dp[i][j] = s3[i+j-1] == s1[i-1] && dp[i-1][j] || s3[i+j-1] == s2[j-1] && dp[i][j-1] 在理解该思路后,也可以将动态规划辅助数组优化至一维 此时:

我们可以将二维的辅助数组优化为一维: dp[i] 表示 s2 的前 j 个字符能够和 s1 当前的前 i 个字符组成 s3 的前 (i+j) 个字符 每次外层循环时,我们需要尝试更新 dp[0],因为现在的 dp[0] 是 dp[i][0],因此 dp[0] 需要= s1[i-1] == s3[i-1] && dp[0] 内层循环时无需任何变化,因为只要我们按 j 递增的方向遍历 j,则在 j 到达j时,dp[j] 确实为dp[i-1][j],而 dp[j-1] 被更新为 dp[i][j-1]

代码

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int len1 = s1.length(), len2 = s2.length();
        if (s3.length() != len1 + len2) return false;

        vector<bool> dp(len2 + 1);
        dp[0] = true;
        for (int i = 1; i <= len2 && dp[i-1]; ++i)
            dp[i] = s3[i-1] == s2[i-1];

        for (int i = 1; i <= len1; ++i)
        {
            dp[0] = dp[0] && s1[i-1] == s3[i-1];
            for (int j = 1; j <= len2; ++j)
            {
                dp[j] = dp[j] && s1[i-1] == s3[i+j-1] || dp[j-1] && s2[j-1] == s3[i+j-1];
            }
        }

        return dp[len2];
    }
};

结语

业精于勤,荒于嬉;行成于思,毁于随。