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?
My Solutions:
方法1: Recursion with memoization
i, j, k分别代表s1,s2,s3三个字符串的起始地址 (1)s3的首字母是来自s1吗?如果是,可以拆解为s1的 i+1 与 s2的j 与s3的Interleaving String子问题。 (2)s3的首字母是来自s2吗?如果是,可以拆解为s2的 j+1 与 s2的j 与s3的Interleaving String子问题。 以上2个条件成立一个,表示结果成立。 Base Case: 如果k超过了s3的length,表示s3是空串,返回TRUE 加一个二维矩阵来记录结果值,这样可以减少不必要的重复计算。
Time complexity: O(m*n), where m is the length of s1 and n is the length of s2. That's a consequence of the fact that each
(i, j)
is computed only once.Space complexity: O(m*n) to keep the double array
memo
.
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if (s1.length() + s2.length() != s3.length()) return false;
int memo[][] = new int[s1.length()][s2.length()];
// initialize all the number to -1
for (int i = 0; i < s1.length(); i++) {
for (int j = 0; j < s2.length(); j++) {
memo[i][j] = -1;
}
}
return getMemory(s1, 0, s2, 0, s3, 0, memo);
}
public boolean getMemory(String s1, int i, String s2, int j, String s3, int k, int[][] memo) {
// if i is at the end of s1
if (i == s1.length()) {
return s2.substring(j).equals(s3.substring(k));
}
// if j is at the end of s2
if (j == s2.length()) {
return s1.substring(i).equals(s3.substring(k));
}
if (memo[i][j] >= 0) {
return memo[i][j] == 1 ? true : false;
}
boolean ans = false;
if (
(s3.charAt(k) == s1.charAt(i) && getMemory(s1, i + 1, s2, j, s3, k + 1, memo))
|| (s3.charAt(k) == s2.charAt(j) && getMemory(s1, i, s2, j + 1, s3, k + 1, memo))
) {
ans = true;
}
memo[i][j] = ans ? 1 : 0;
return ans;
}
}
方法2:Using 2D Dynamic Programming
D[i][j]: 定义为s1 (前i个字符) s2(前j个字符) s3(i+j 个字符) 是不是交叉字符
s1 s3 首字母相同,继续查i -1 与 i + j -1 是否isInterleave
s2 s3 首字母相同,继续查j -1 与 i + j -1 是否isInterleave
递推公式: (s1.i == s3.(i+j) && D[i-1][j]) || (s2.j == s3.(i+j) && D[i][j - 1])
Time complexity: O(m*n). dp array of size m*n is filled.
Space complexity: O(m*n). 2D dp of size (m+1)*(n+1) is required.
boolean dp[][] = new boolean[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) {
for (int j = 0; j <= s2.length(); j++) {
if (i == 0 && j == 0) {
dp[i][j] = true;
} else if (i == 0) {
dp[i][j] = dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1);
} else if (j == 0) {
dp[i][j] = dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1);
} else {
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));
}
}
}
return dp[s1.length()][s2.length()];
方法3:Using 1D Dynamic Programming
Use only 1D dp array to store the results of the prefixes of the strings processed so far. Instead of maintaining a 2D array, maintain a 1D array only and update the array's element dp[i] when needed using dp[i-1] and the previous value of dp[i].
boolean dp[] = new boolean[s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) {
for (int j = 0; j <= s2.length(); j++) {
if (i == 0 && j == 0) {
dp[j] = true;
} else if (i == 0) {
dp[j] = dp[j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1);
} else if (j == 0) {
dp[j] = dp[j] && s1.charAt(i - 1) == s3.charAt(i + j - 1);
} else {
dp[j] = (dp[j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) || (dp[j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1));
}
}
}
return dp[s2.length()];
Last updated