The Interleaving String problem requires determining whether a string can be formed by interleaving two other strings while preserving the order of characters from each string.

Problem

Given strings s1, s2, and s3, determine whether s3 can be formed by interleaving s1 and s2. An interleaving must preserve the relative order of characters from both s1 and s2.

Example(s)

Consider the following example to understand the expected input and output.

Input

s1 = "aabcc"
s2 = "dbbca"
s3 = "aadbbcbcac"

Output

true

Explanation

s3 = "aa" + "dbbc" + "bc" + "a" + "c"
The characters from s1 and s2 are interleaved while preserving the original order of characters within each string.

Solution

This problem can be solved using Dynamic Programming with Memoization.

First, the lengths of s1 and s2 must add up to the length of s3. Otherwise, forming s3 is impossible.

We use i and j to represent the current positions in s1 and s2. The corresponding position in s3 is i + j, because we have already consumed i characters from s1 and j characters from s2.

At each position, we have two possible choices. If the current character of s1 matches the corresponding character of s3, we can take the character from s1. Similarly, if the current character of s2 matches, we can take the character from s2.

If either choice can successfully reach the end of s3, the strings can be interleaved. We store each (i, j) state in memo to avoid recalculating the same state.
class Solution {

    public boolean isInterleave(String s1, String s2, String s3) {
        if (s1.length() + s2.length() != s3.length())
            return false;

        Boolean[][] memo = new Boolean[s1.length() + 1][s2.length() + 1];
        return isInterleaveHelper(s1, s2, s3, 0, 0, memo);
    }

    private boolean isInterleaveHelper(String s1, String s2, String s3, int i, int j, Boolean[][] memo) {
        // All characters from s1 and s2 have been used
        if (i == s1.length() && j == s2.length())
            return true;

        // Return the cached result
        if (memo[i][j] != null)
            return memo[i][j];

        int k = i + j;
        boolean result = false;

        // Take the current character from s1
        if (i < s1.length() && s1.charAt(i) == s3.charAt(k))
            result = isInterleaveHelper(s1, s2, s3, i + 1, j, memo);

        // Take the current character from s2
        if (!result && j < s2.length() && s2.charAt(j) == s3.charAt(k))
            result = isInterleaveHelper(s1, s2, s3, i, j + 1, memo);

        return memo[i][j] = result;
    }
}

Complexity

There are at most m × n unique states, where m and n are the lengths of s1 and s2. Each state is processed once, resulting in O(m × n) time complexity.

The memoization table and recursion stack require O(m × n) space.
Nagesh Chauhan

Nagesh Chauhan

Principal Software Engineer • Java • Python • Distributed Systems • AI/ML

Principal Software Engineer with 14+ years of experience designing and delivering large-scale distributed systems, cloud-native applications, and AI-powered platforms.

Passionate about solving complex engineering problems using strong data structures and algorithms, along with expertise in Java, Spring Boot, Python, System Design, Microservices, Cloud, Kafka, Elasticsearch, and Generative AI.

Share this Article

💬 Comments

Join the Discussion