[LeetCode] 97. Interleaving String
Given strings s1
, s2
, and s3
, find whether s3
is formed by an interleaving of s1
and s2
.
An interleaving of two strings s
and t
is a configuration where they are divided into non-empty substrings such that:
s = s1 + s2 + ... + sn
t = t1 + t2 + ... + tm
|n - m| <= 1
- The interleaving is
s1 + t1 + s2 + t2 + s3 + t3 + ...
ort1 + s1 + t2 + s2 + t3 + s3 + ...
Note: a + b
is the concatenation of strings a
and b
.
Example 1:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac" Output: true
Example 2:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc" Output: false
Example 3:
Input: s1 = "", s2 = "", s3 = "" Output: true
Constraints:
0 <= s1.length, s2.length <= 100
0 <= s3.length <= 200
s1
,s2
, ands3
consist of lowercase English letters.
Follow up: Could you solve it using only O(s2.length)
additional memory space?
交错字符串。
给定三个字符串 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 连接。来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/interleaving-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题意是给 s1, s2 和 s3,验证 s3 是否是由 s1 和 s2 交错组成的。这是典型的二维 DP 题,设 dp[i][j] 是 s1 的前 i 个字符 + s2 的前 j 个字符组成的结果是否能跟 s3 的前 i + j 个字符匹配。首先排除 corner case,如果 s1 + s2 的长度不等于 s3,则说明是不行的。另外,还需要先在二维数组中计算出当 s1 为空和当 s2 为空的时候相对应的 DP 值。最后 normal case 是这两种其中一种为 true 则 dp[i][j] 为 true。
- s1 的前 i - 1 个字符 + s2 的前 j 个字符
- s1 的前 i 个字符 + s2 的前 j - 1 个字符
其实也就是 s1 和 s2 拼接出来的部分的最后一个字符可来自于 s1 也可来自于 s2,只要有一种情况为 true 则整体就为 true。这里我还是提供自上而下和自下而上两种实现方式,时间空间复杂度相同。
时间O(mn)
空间O(mn)
DP自上而下
1 class Solution { 2 int[][] memo; 3 4 public boolean isInterleave(String s1, String s2, String s3) { 5 int m = s1.length(); 6 int n = s2.length(); 7 // corner case 8 if (m + n != s3.length()) { 9 return false; 10 } 11 12 // normal case 13 memo = new int[m + 1][n + 1]; 14 for (int[] row : memo) { 15 Arrays.fill(row, -1); 16 } 17 return dp(s1, 0, s2, 0, s3); 18 } 19 20 private boolean dp(String s1, int i, String s2, int j, String s3) { 21 int k = i + j; 22 // base case 23 if (k == s3.length()) { 24 return true; 25 } 26 27 if (memo[i][j] != -1) { 28 return memo[i][j] == 1 ? true : false; 29 } 30 boolean res = false; 31 if (i < s1.length() && s1.charAt(i) == s3.charAt(k)) { 32 res = dp(s1, i + 1, s2, j, s3); 33 } 34 if (j < s2.length() && s2.charAt(j) == s3.charAt(k)) { 35 res = res || dp(s1, i, s2, j + 1, s3); 36 } 37 memo[i][j] = res == true ? 1 : 0; 38 return res; 39 } 40 }
DP自下而上
1 class Solution { 2 public boolean isInterleave(String s1, String s2, String s3) { 3 int m = s1.length(); 4 int n = s2.length(); 5 // corner case 6 if ((m + n) != s3.length()) { 7 return false; 8 } 9 10 // normal case 11 boolean[][] dp = new boolean[m + 1][n + 1]; 12 dp[0][0] = true; 13 14 // 考虑当 s2 为空的时候,s1 能组合吗 15 for (int i = 1; i < dp.length; i++) { 16 dp[i][0] = dp[i - 1][0] && (s1.charAt(i - 1) == s3.charAt(i - 1)); 17 } 18 19 // 考虑当 s1 为空的时候,s2 能组合吗 20 for (int i = 1; i < dp[0].length; i++) { 21 dp[0][i] = dp[0][i - 1] && (s2.charAt(i - 1) == s3.charAt(i - 1)); 22 } 23 24 // normal case 25 for (int i = 1; i < dp.length; i++) { 26 for (int j = 1; j < dp[0].length; j++) { 27 dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) 28 || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1)); 29 } 30 } 31 return dp[m][n]; 32 } 33 }