题目

给定三个字符串 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: image.png 输入: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
s1、s2、和 s3 都由小写英文字母组成

进阶:您能否仅使用 O(s2.length) 额外的内存空间来解决它?

思路

参考的 这个 题解,转换成了路径问题,一放到矩阵里立马就好理解了,真的很妙。

代码

  1. class Solution {
  2. public boolean isInterleave(String s1, String s2, String s3) {
  3. int n = s1.length();
  4. int m = s2.length();
  5. if (n + m != s3.length()) return false;
  6. // dp[i][j]表示能否使用s1的前i位和s2的前j位交错匹配出s3,最后返回dp[n][m]
  7. boolean[][] dp = new boolean[n + 1][m + 1];
  8. dp[0][0] = true;
  9. // 初始化第一列,表示只使用s1匹配s3
  10. for (int i = 1; i < n + 1; ++i) {
  11. if (s1.charAt(i - 1) == s3.charAt(i - 1)) {
  12. dp[i][0] = true;
  13. } else { // 因为s3只单独匹配s1,所以中间只要有一个字母不匹配了,后面的也一定不匹配了
  14. break;
  15. }
  16. }
  17. // 初始化第一行,表示只使用s2匹配s3
  18. for (int i = 1; i < m + 1; ++i) {
  19. if (s2.charAt(i - 1) == s3.charAt(i - 1)) {
  20. dp[0][i] = true;
  21. } else {
  22. break;
  23. }
  24. }
  25. for (int i = 1; i < n + 1; ++i) {
  26. for (int j = 1; j < m + 1; ++j) {
  27. // 交错字符串体现到矩阵中就是只能向下和向右转移,每一个dp值可以从它上面和左面的值转移过来
  28. // dp[i][j]为true需要最少满足下面两个条件之一:
  29. // 使用s1的第i个字母匹配s3的第i+j个字母,同时使用s1的前i-1个字母和s2的前j个字母可以匹配s3的前i+j-1个字母
  30. // 使用s2的第j个字母匹配s3的第i+j个字母,同时使用s1的前i个字母和s2的前j-1个字母可以匹配s3的前i+j-1个字母
  31. dp[i][j] = dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1) || dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1);
  32. }
  33. }
  34. return dp[n][m];
  35. }
  36. }