97. Interleaving String
- Goal: Determine if string
s3
is formed by an interleaving of stringss1
ands2
. > Interleaving: Combining two strings by merging their characters while preserving the original order of characters from each string. - Constraints:
0 <= s1.length, s2.length <= 100
0 <= s3.length <= 200
- All strings consist of lowercase English letters.
- Follow-up: Can you solve it using only O(s2.length) additional memory space?
Understanding the Problem
Given three strings s1
, s2
, and
s3
, we need to check if s3
can be formed by
interleaving s1
and s2
. An
interleaving means that we can shuffle s1
and s2
together, maintaining the order of characters in
each string, to get s3
.
Key Points:
- Order Preservation: The order of characters in
s1
ands2
must be maintained ins3
. - Interleaving: At each step, you can choose a
character from either
s1
ors2
.
Example
1 | s1 = "aabcc" |
output:
true
Quick Steps for Solving the Problem
1. Check Lengths
- Condition: If
s1.length + s2.length != s3.length
, returnfalse
. - Rationale: If the total length doesn't match, it's
impossible for
s3
to be an interleaving ofs1
ands2
.
2. Initialise a 2D DP Table
- Purpose: Use Dynamic Programming to store subproblem results.
- Structure: Create a 2D array
dp
of size(s1.length + 1) x (s2.length + 1)
. - Base Case: Set
dp[0][0] = true
(empty strings can form an empty string).
3. Fill the First Row and First Column
- First Column (
dp[i][0]
):dp[i][0] = dp[i - 1][0] && s1[i - 1] == s3[i - 1]
- Meaning: Can
s3
up to lengthi
be formed bys1
up to lengthi
?
- First Row (
dp[0][j]
):dp[0][j] = dp[0][j - 1] && s2[j - 1] == s3[j - 1]
- Meaning: Can
s3
up to lengthj
be formed bys2
up to lengthj
?
4. Fill the Rest of the DP Table
- For Each Cell
dp[i][j]
:- Option 1: If
dp[i - 1][j]
istrue
ands1[i - 1] == s3[i + j - 1]
, thendp[i][j] = true
.- Meaning: If we can form
s3
up toi + j - 1
by addings1[i - 1]
.
- Meaning: If we can form
- Option 2: If
dp[i][j - 1]
istrue
ands2[j - 1] == s3[i + j - 1]
, thendp[i][j] = true
.- Meaning: If we can form
s3
up toi + j - 1
by addings2[j - 1]
.
- Meaning: If we can form
- Else:
dp[i][j] = false
.
- Option 1: If
5. Return the Result
- Answer:
dp[s1.length][s2.length]
- Meaning: Whether
s3
can be formed by interleavings1
ands2
.
- Meaning: Whether
Analogy to Simplify Understanding
Imagine you have two queues of characters:
- Queue A (
s1
): A line of people waiting in order. - Queue B (
s2
): Another line of people waiting in order. - Goal: Form a new line (
s3
) by merging these two queues, taking one person at a time from either queue, without changing the order in each queue.
Rules:
- You can pick the next person from either Queue A or Queue B.
- You cannot skip or rearrange people within a queue.
- The final line (
s3
) must have everyone from both queues, in some order that respects the above rules.
Step-by-Step Implementation
1. Check Total Length
1 | if (s1.length + s2.length !== s3.length) return false; |
2. Initialise DP Table
1 | const N = s1.length; |
3. Fill First Row and First Column
Fill First Column
(dp[i][0]
)
1 | for (let i = 1; i <= N; i++) { |
Fill First Row (dp[0][j]
)
1 | for (let j = 1; j <= M; j++) { |
4. Fill the Rest of the DP Table
1 | for (let i = 1; i <= N; i++) { |
5. Return the Result
1 | return dp[N][M]; |
JavaScript Implementation
1 | /** |
Detailed Explanation
Understanding the DP Table
- Dimensions:
(s1.length + 1) x (s2.length + 1)
dp[i][j]
Meaning: Whethers3
up to lengthi + j
can be formed by interleavings1
up to lengthi
ands2
up to lengthj
.
Base Cases
dp[0][0] = true
: Emptys1
ands2
can form emptys3
.- First Row and Column:
- We check if
s3
up to lengthi
orj
matchess1
ors2
respectively.
- We check if
Filling the DP Table
At each cell dp[i][j]
, we consider two
possibilities:
- Taking a character from
s1
:- If
dp[i - 1][j]
istrue
(we can forms3
up toi + j - 2
withs1[0..i-2]
ands2[0..j-1]
). - And if
s1[i - 1]
matchess3[i + j - 1]
.
- If
- Taking a character from
s2
:- If
dp[i][j - 1]
istrue
(we can forms3
up toi + j - 2
withs1[0..i-1]
ands2[0..j-2]
). - And if
s2[j - 1]
matchess3[i + j - 1]
.
- If
If either possibility is true
, we set
dp[i][j] = true
.
Example Walkthrough
Let's consider s1 = "abc"
, s2 = "def"
,
s3 = "adbcef"
.
- dp[1][1]:
dp[0][1]
isfalse
, so first condition fails.dp[1][0]
istrue
ands1[0] == s3[1]
('a' == 'd'
) isfalse
.dp[1][1]
remainsfalse
.
- dp[1][2]:
- Similar checks,
dp[1][2]
remainsfalse
.
- Similar checks,
- dp[2][1]:
dp[1][1]
isfalse
.dp[2][0]
isfalse
.dp[2][1]
remainsfalse
.
- dp[3][3]:
dp[2][3]
isfalse
.dp[3][2]
istrue
ands2[2] == s3[5]
('f' == 'f'
) istrue
.- So,
dp[3][3] = true
.
Final Result: Since dp[3][3] = true
,
s3
is an interleaving of s1
and
s2
.
Summary
- Dynamic Programming: We use a 2D DP table to keep
track of possible interleavings up to each point in
s1
ands2
. - Key Concepts:
- Preserving Order: We must maintain the sequence of
characters in
s1
ands2
. - State Transition: Each state depends on previous
states, considering characters from
s1
ands2
.
- Preserving Order: We must maintain the sequence of
characters in
- Analogy: Merging two queues without changing the order within each queue.
- Time Complexity: O(N * M)
- Space Complexity: O(N * M), can be optimised to O(M)
Further Understanding and Tips
Why Use dp[i][j]
?
dp[i][j]
represents a subproblem: Whethers3
up to lengthi + j
can be formed by interleavings1
up to lengthi
ands2
up to lengthj
.- Breaking Down the Problem: By solving smaller subproblems, we build up to the final solution.
Handling Edge Cases
- Empty Strings: If
s1
ors2
is empty, we need to check ifs3
matches the other string. - Initialization: Properly initializing the first row and column is crucial for these cases.
Visualization
- DP Table as a Grid: Visualise the DP table as a grid where each cell represents a state.
- Path Finding: Finding a path from
dp[0][0]
todp[N][M]
corresponds to interleavings1
ands2
to forms3
.
Practice Problems for 2D Dynamic Programming
To strengthen your understanding of 2D DP, consider practicing the following problems:
- LeetCode 62: Unique Paths
- LeetCode 1143: Longest Common Subsequence
- LeetCode 221: Maximal Square
- LeetCode 72: Edit Distance
Final Thoughts
Dynamic Programming can be challenging, but breaking down the problem into subproblems and understanding the state transitions makes it manageable. Remember to:
- Define the DP State Clearly: Know what each element in your DP table represents.
- Initialise Properly: Base cases are crucial for correct results.
- Think Recursively: How can you build the current state from previous states?
- Practice: The more problems you solve, the better you'll understand DP patterns.
Happy coding!