Problem Statement

Interleaving String

You are given three strings: s1, s2, and s3. The question is whether you can build s3 by zipping s1 and s2 together. "Zipping" here means you take characters from s1 and s2 in some mixed order, but you never scramble the order inside either one. The letters of s1 stay in their original sequence, the letters of s2 stay in their original sequence, and together they fill s3 from left to right. Think of two people dealing cards into one shared pile. Each person keeps their own deck in order, but they can take turns however they like. We want to know if some pattern of turns produces exactly s3.

hardDynamic ProgrammingDynamic ProgrammingTime: O(m*n) · Space: O(m*n)

Signals to notice

interleave two strings to form a thirdorder within each string preservedtwo source pointers

Brute force first

Recursively try taking the next character from s1 or s2. Two choices at each position, exponential branching. It is a fair place to begin because it matches the surface of the question, yet it does not capture the deeper structure that makes the problem simpler.

The key insight

2D DP: dp[i][j] = can the first i chars of s1 and first j chars of s2 form the first (i+j) chars of s3? Check if s3[i+j-1] matches s1[i-1] (extend from dp[i-1][j]) or s2[j-1] (extend from dp[i][j-1]). Instead of recomputing the world every time, you preserve just enough context to let the next decision become obvious.

Trace it on s1="aabcc", s2="dbbca", s3="aadbbcbcac"

Length check: m=5, n=5, 5+5==10==len(s3) -> proceed. dp[0][0]=True. (i=rows index s1, j=cols index s2.)
First col (only s1): dp[1][0]=T (s1[0]='a'==s3[0]='a'), dp[2][0]=T (s1[1]='a'==s3[1]='a'), dp[3][0]=F (s1[2]='b'!=s3[2]='d'). First row (only s2): dp[0][1]=F (s2[0]='d'!=s3[0]='a'), so whole top row stays F.
Row i=2 (consumed 'aa' from s1): dp[2][1]=T from dp[2][0] since s2[0]='d'==s3[2]='d'; dp[2][2]=T from dp[2][1] since s2[1]='b'==s3[3]='b'; dp[2][3]=T from dp[2][2] since s2[2]='b'==s3[4]='b'. Matches s3[0:5]='aadbb'.
dp[3][3]=F: from dp[2][3], s1[2]='b'!=s3[5]='c'; from dp[3][2], dp[3][2] is F. But dp[2][4]=T from dp[2][3] since s2[3]='c'==s3[5]='c' ('aadbbc'), and dp[3][4]=T from dp[2][4] since s1[2]='b'==s3[6]='b' ('aadbbcb').
dp[4][4]=T from dp[3][4] since s1[3]='c'==s3[7]='c' ('aadbbcbc'); dp[4][5]=T from dp[4][4] since s2[4]='a'==s3[8]='a' ('aadbbcbca').
dp[5][5]=T from dp[4][5] since s1[4]='c'==s3[9]='c' ('aadbbcbcac'). Note dp[5][4]=F, so the True path runs through dp[4][5], not dp[5][4].
return dp[5][5]=True. Valid interleave: aa(s1) | dbb(s2) | b(s1) | c(s1) | a(s2) | c(s1).

What must stay true

Position (i,j) in the DP table corresponds to having consumed i characters from s1 and j characters from s2, matching s3[0.i+j-1]. The next character in s3 must come from either s1 or s2. As long as that statement keeps holding, you can trust the steps built on top of it.

Shape of the loop

if len(s1)+len(s2) != len(s3): return False
dp[0][0] = True
fill first row/col by prefix-matching s2 / s1 against s3
for i in 1..m: for j in 1..n:
  dp[i][j] = (dp[i-1][j] and s1[i-1]==s3[i+j-1]) or (dp[i][j-1] and s2[j-1]==s3[i+j-1])
return dp[m][n]

Pseudocode only — the full worked solution lives in the Solution tab.

Easy way to go wrong

Forgetting to check s1.length + s2.length == s3.length first — if lengths don't add up, interleaving is impossible regardless. Most mistakes here are not about syntax; they come from losing track of what your state, pointer, or structure is supposed to mean.

Dynamic Programming Pattern