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 s and t are divided into n and m substrings respectively, such that:
s = s1 + s2 + ... + snt = t1 + t2 + ... + tm|n - m| <= 1s1 + t1 + s2 + t2 + ... or t1 + s1 + t2 + s2 + ...Note: a + b is the concatenation of strings a and b.
Example 1:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
Output: true
Explanation: One way to obtain s3 is:
Split s1 into s1 = "aa" + "bc" + "c", and s2 into s2 = "dbbc" + "a".
Interleaving the two splits, we get "aa" + "dbbc" + "bc" + "a" + "c" = "aadbbcbcac"
Example 2:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
Output: false
Example 3:
Input: s1 = "", s2 = "", s3 = ""
Output: true
Think of this as navigating a 2D grid where:
s2s1s3Key Insight:
dp[i][j] = can first i chars of s1 and first j chars of s2 form first i+j chars of s3?s1[i-1]) or left (using s2[j-1])Length check:
s1.length + s2.length != s3.length → return falseCreate DP table:
(m+1) × (n+1) where m = s1.length, n = s2.lengthdp[i][j] = can s1[0..i-1] and s2[0..j-1] form s3[0..i+j-1]Base case:
dp[0][0] = true (empty strings)Recurrence:
dp[i][j] = (s1[i-1] == s3[i+j-1] && dp[i-1][j]) ||
(s2[j-1] == s3[i+j-1] && dp[i][j-1])
Return dp[m][n]
i+j-1 (combining positions from both strings)This problem demonstrates:
s3[i+j-1] corresponds to position when using i chars from s1 and j from s21class Solution {
2 // Solution 1: 2D Dynamic Programming
3 public boolean isInterleave(String s1, String s2, String s3) {
4 int m = s1.length();
5 int n = s2.length();
6
7 // Check length
8 if (m + n != s3.length()) {
9 return false;
10 }
11
12 // dp[i][j] = can s1[0..i-1] and s2[0..j-1] form s3[0..i+j-1]
13 boolean[][] dp = new boolean[m + 1][n + 1];
14
15 // Base case: empty strings
16 dp[0][0] = true;
17
18 // Fill first column (only using s1)
19 for (int i = 1; i <= m; i++) {
20 dp[i][0] = dp[i - 1][0] && s1.charAt(i - 1) == s3.charAt(i - 1);
21 }
22
23 // Fill first row (only using s2)
24 for (int j = 1; j <= n; j++) {
25 dp[0][j] = dp[0][j - 1] && s2.charAt(j - 1) == s3.charAt(j - 1);
26 }
27
28 // Fill the rest of the table
29 for (int i = 1; i <= m; i++) {
30 for (int j = 1; j <= n; j++) {
31 // Can we form s3[i+j-1]?
32 // Option 1: Use s1[i-1]
33 boolean matchS1 = s1.charAt(i - 1) == s3.charAt(i + j - 1) && dp[i - 1][j];
34 // Option 2: Use s2[j-1]
35 boolean matchS2 = s2.charAt(j - 1) == s3.charAt(i + j - 1) && dp[i][j - 1];
36
37 dp[i][j] = matchS1 || matchS2;
38 }
39 }
40
41 return dp[m][n];
42 }
43
44 // Solution 2: 1D DP (Space Optimized)
45 public boolean isInterleaveOptimized(String s1, String s2, String s3) {
46 int m = s1.length();
47 int n = s2.length();
48
49 if (m + n != s3.length()) {
50 return false;
51 }
52
53 // Only need current and previous row
54 boolean[] dp = new boolean[n + 1];
55 dp[0] = true;
56
57 // Fill first row
58 for (int j = 1; j <= n; j++) {
59 dp[j] = dp[j - 1] && s2.charAt(j - 1) == s3.charAt(j - 1);
60 }
61
62 // Fill rest of table row by row
63 for (int i = 1; i <= m; i++) {
64 // Update first column
65 dp[0] = dp[0] && s1.charAt(i - 1) == s3.charAt(i - 1);
66
67 for (int j = 1; j <= n; j++) {
68 boolean matchS1 = s1.charAt(i - 1) == s3.charAt(i + j - 1) && dp[j];
69 boolean matchS2 = s2.charAt(j - 1) == s3.charAt(i + j - 1) && dp[j - 1];
70 dp[j] = matchS1 || matchS2;
71 }
72 }
73
74 return dp[n];
75 }
76
77 // Solution 3: DFS with Memoization
78 public boolean isInterleaveDFS(String s1, String s2, String s3) {
79 if (s1.length() + s2.length() != s3.length()) {
80 return false;
81 }
82
83 Boolean[][] memo = new Boolean[s1.length() + 1][s2.length() + 1];
84 return dfs(s1, s2, s3, 0, 0, memo);
85 }
86
87 private boolean dfs(String s1, String s2, String s3, int i, int j, Boolean[][] memo) {
88 // If we've matched all of s3
89 if (i + j == s3.length()) {
90 return true;
91 }
92
93 // Check memo
94 if (memo[i][j] != null) {
95 return memo[i][j];
96 }
97
98 boolean result = false;
99
100 // Try matching with s1
101 if (i < s1.length() && s1.charAt(i) == s3.charAt(i + j)) {
102 result = dfs(s1, s2, s3, i + 1, j, memo);
103 }
104
105 // Try matching with s2
106 if (!result && j < s2.length() && s2.charAt(j) == s3.charAt(i + j)) {
107 result = dfs(s1, s2, s3, i, j + 1, memo);
108 }
109
110 memo[i][j] = result;
111 return result;
112 }
113}
114