Saturday, November 16, 2024
Google search engine
HomeData Modelling & AIFind if a string is interleaved of two other strings | DP-33

Find if a string is interleaved of two other strings | DP-33

Given three strings A, B and C. Write a function that checks whether C is an interleaving of A and B. C is said to be interleaving A and B, if it contains all and only characters of A and B and order of all characters in individual strings is preserved. 

Example: 

Input: strings: "XXXXZY", "XXY", "XXZ"
Output: XXXXZY is interleaved of XXY and XXZ
The string XXXXZY can be made by
interleaving XXY and XXZ
String: XXXXZY
String 1: XX Y
String 2: XX Z

Input: strings: "XXY", "YX", "X"
Output: XXY is not interleaved of YX and X
XXY cannot be formed by interleaving YX and X.
The strings that can be formed are YXX and XYX
Recommended Practice

Method 1: Recursion. 
Approach: A simple solution is discussed here: Check whether a given string is an interleaving of two other given string
The simple solution doesn’t work if the strings A and B have some common characters. For example, let the given string be A and the other strings be B and C. Let A = “XXY”, string B = “XXZ” and string C = “XXZXXXY”. Create a recursive function that takes parameters A, B, and C. To handle all cases, two possibilities need to be considered.

  1. If the first character of C matches the first character of A, we move one character ahead in A and C and recursively check.
  2. If the first character of C matches the first character of B, we move one character ahead in B and C and recursively check.

If any of the above function returns true or A, B and C are empty then return true else return false.
Thanks to Frederic for suggesting this approach.

C++




bool isInterleaved(string A, string B, string C) {
    // Base Case: If all strings are empty
    if (A.empty() && B.empty() && C.empty()) {
        return true;
    }
 
    // If C is empty and any of the two strings is not empty
    if (C.empty()) {
        return false;
    }
 
    // If any of the above mentioned two possibilities is true,
    // then return true, otherwise false
    return ((C[0] == A[0]) && isInterleaved(A.substr(1), B, C.substr(1)))
            || ((C[0] == B[0]) && isInterleaved(A, B.substr(1), C.substr(1)));
}


C




// A simple recursive function to check
// whether C is an interleaving of A and B
bool isInterleaved(
    char* A, char* B, char* C)
{
    // Base Case: If all strings are empty
    if (!(*A || *B || *C))
        return true;
 
    // If C is empty and any of the
    // two strings is not empty
    if (*C == '\0')
        return false;
 
    // If any of the above mentioned
    // two possibilities is true,
    // then return true, otherwise false
    return ((*C == *A) && isInterleaved(
                              A + 1, B, C + 1))
           || ((*C == *B) && isInterleaved(
                                 A, B + 1, C + 1));
}


Java




public static boolean isInterleaved(String A, String B, String C) {
    // Base Case: If all strings are empty
    if (A.isEmpty() && B.isEmpty() && C.isEmpty()) {
        return true;
    }
 
    // If C is empty and any of the two strings is not empty
    if (C.isEmpty()) {
        return false;
    }
 
    // If any of the above mentioned two possibilities is true,
    // then return true, otherwise false
    return (C.charAt(0) == A.charAt(0) && isInterleaved(
            A.substring(1), B, C.substring(1)))
            || (C.charAt(0) == B.charAt(0) && isInterleaved(
            A, B.substring(1), C.substring(1)));
}


Python3




def isInterleaved(A, B, C):
    # Base Case: If all strings are empty
    if not A and not B and not C:
        return True
 
    # If C is empty and any of the two strings is not empty
    if not C:
        return False
 
    # If the first character of C matches the first character of A,
    # then recursively check the rest of A and C
    if A and C[0] == A[0]:
        return isInterleaved(A[1:], B, C[1:])
 
    # If the first character of C matches the first character of B,
    # then recursively check the rest of B and C
    if B and C[0] == B[0]:
        return isInterleaved(A, B[1:], C[1:])
 
    # If none of the above conditions are met, then C cannot be interleaved
    # from A and B
    return False
     
      
# A function to run test cases
def test(A, B, C):
  
    if (isInterleaved(A, B, C)):
        print(C, "is interleaved of", A, "and", B)
    else:
        print(C, "is not interleaved of", A, "and", B)
  
# Driver Code
if __name__ == '__main__':
    test("XXY", "XXZ", "XXZXXXY")
    test("XY", "WZ", "WZXY")
    test("XY", "X", "XXY")
    test("YX", "X", "XXY")
    test("XXY", "XXZ", "XXXXZY")


C#




// C# Equivalent
public static bool IsInterleaved(string A, string B, string C)
{
    // Base Case: If all strings are empty
    if (string.IsNullOrEmpty(A) && string.IsNullOrEmpty(B) && string.IsNullOrEmpty(C))
    {
        return true;
    }
 
    // If C is empty and any of the two strings is not empty
    if (string.IsNullOrEmpty(C))
    {
        return false;
    }
 
    // If any of the above mentioned two possibilities is true,
    // then return true, otherwise false
    return (C[0] == A[0] && IsInterleaved(A.Substring(1), B, C.Substring(1)))
            || (C[0] == B[0] && IsInterleaved(A, B.Substring(1), C.Substring(1)));
}


Javascript




function isInterleaved(A, B, C) {
    // Base Case: If all strings are empty
    if (!A && !B && !C) {
        return true;
    }
 
    // If C is empty and any of the two strings is not empty
    if (!C) {
        return false;
    }
 
    // If the first character of C matches the first character of A,
    // then recursively check the rest of A and C
    if (A && C[0] == A[0]) {
        return isInterleaved(A.substring(1), B, C.substring(1));
    }
 
    // If the first character of C matches the first character of B,
    // then recursively check the rest of B and C
    if (B && C[0] == B[0]) {
        return isInterleaved(A, B.substring(1), C.substring(1));
    }
 
    // If none of the above conditions are met, then C cannot be interleaved
    // from A and B
    return false;
}
 
// A function to run test cases
function test(A, B, C) {
    if (isInterleaved(A, B, C)) {
        console.log(`${C} is interleaved of ${A} and ${B}`);
    } else {
        console.log(`${C} is not interleaved of ${A} and ${B}`);
    }
}
 
// Driver Code
test("XXY", "XXZ", "XXZXXXY");
test("XY", "WZ", "WZXY");
test("XY", "X", "XXY");
test("YX", "X", "XXY");
test("XXY", "XXZ", "XXXXZY");


Complexity Analysis: 

  • Time Complexity: O(2^n), where n is the length of the given string. 
  • Space Complexity: O(1). 
    The space complexity is constant.

Method 2: Dynamic Programming. 
Approach: The above recursive solution certainly has many overlapping sub-problems. For example, if we consider A = “XXX”, B = “XXX” and C = “XXXXXX” and draw a recursion tree, there will be many overlapping subproblems. Therefore, like any other typical Dynamic Programming problems, we can solve it by creating a table and store results of sub-problems in a bottom-up manner. The top-down approach of the above solution can be modified by adding a Hash Map.

Algorithm: 

  1. Create a DP array (matrix) of size M*N, where m is the size of the first string and n is the size of the second string. Initialize the matrix to false.
  2. If the sum of sizes of smaller strings is not equal to the size of the larger string then return false and break the array as they cant be the interleaved to form the larger string.
  3. Run a nested loop the outer loop from 0 to m and the inner loop from 0 to n. Loop counters are i and j.
  4. If the values of i and j are both zeroes then mark dp[i][j] as true. If the value of i is zero and j is non zero and the j-1 character of B is equal to j-1 character of C the assign dp[i][j] as dp[i][j-1] and similarly if j is 0 then match i-1 th character of C and A and if it matches then assign dp[i][j] as dp[i-1][j].
  5. Take three characters x, y, z as (i-1)th character of A and (j-1)th character of B and (i + j – 1)th character of C.
  6. if x matches with z and y does not match with z then assign dp[i][j] as dp[i-1][j] similarly if x is not equal to z and y is equal to z then assign dp[i][j] as dp[i][j-1]
  7. if x is equal to y and y is equal to z then assign dp[i][j] as bitwise OR of dp[i][j-1] and dp[i-1][j].
  8. return value of dp[m][n].

Thanks to Abhinav Ramana for suggesting this method of implementation. 

C++




// A Dynamic Programming based program
// to check whether a string C is
// an interleaving of two other
// strings A and B.
#include <iostream>
#include <string.h>
using namespace std;
 
// The main function that
// returns true if C is
// an interleaving of A
// and B, otherwise false.
bool isInterleaved(
    char* A, char* B, char* C)
{
    // Find lengths of the two strings
    int M = strlen(A), N = strlen(B);
 
    // Let us create a 2D table
    // to store solutions of
    // subproblems.  C[i][j] will
    // be true if C[0..i+j-1]
    // is an interleaving of
    // A[0..i-1] and B[0..j-1].
    bool IL[M + 1][N + 1];
 
    // Initialize all values as false.
    memset(IL, 0, sizeof(IL));
 
    // C can be an interleaving of
    // A and B only of the sum
    // of lengths of A & B is equal
    // to the length of C.
    if ((M + N) != strlen(C))
        return false;
 
    // Process all characters of A and B
    for (int i = 0; i <= M; ++i) {
        for (int j = 0; j <= N; ++j) {
            // two empty strings have an
            // empty string as interleaving
            if (i == 0 && j == 0)
                IL[i][j] = true;
 
            // A is empty
            else if (i == 0) {
                if (B[j - 1] == C[j - 1])
                    IL[i][j] = IL[i][j - 1];
            }
 
            // B is empty
            else if (j == 0) {
                if (A[i - 1] == C[i - 1])
                    IL[i][j] = IL[i - 1][j];
            }
 
            // Current character of C matches
            // with current character of A,
            // but doesn't match with current
            // character of B
            else if (
                A[i - 1] == C[i + j - 1]
                && B[j - 1] != C[i + j - 1])
                IL[i][j] = IL[i - 1][j];
 
            // Current character of C matches
            // with current character of B,
            // but doesn't match with current
            // character of A
            else if (
                A[i - 1] != C[i + j - 1]
                && B[j - 1] == C[i + j - 1])
                IL[i][j] = IL[i][j - 1];
 
            // Current character of C matches
            // with that of both A and B
            else if (
                A[i - 1] == C[i + j - 1]
                && B[j - 1] == C[i + j - 1])
                IL[i][j]
                    = (IL[i - 1][j]
                       || IL[i][j - 1]);
        }
    }
 
    return IL[M][N];
}
 
// A function to run test cases
void test(char* A, char* B, char* C)
{
    if (isInterleaved(A, B, C))
        cout << C << " is interleaved of "
             << A << " and " << B << endl;
    else
        cout << C << " is not interleaved of "
             << A << " and " << B << endl;
}
 
// Driver program to test above functions
int main()
{
    test("XXY", "XXZ", "XXZXXXY");
    test("XY", "WZ", "WZXY");
    test("XY", "X", "XXY");
    test("YX", "X", "XXY");
    test("XXY", "XXZ", "XXXXZY");
    return 0;
}


Java




// A Dynamic Programming based program
// to check whether a string C is
// an interleaving of two other
// strings A and B.
import java.io.*;
import java.util.*;
import java.lang.*;
 
class GFG{
 
// The main function that returns
// true if C is an interleaving of A
// and B, otherwise false. 
static boolean isInterleaved(String A, String B,
                             String C)
{
     
    // Find lengths of the two strings
    int M = A.length(), N = B.length();
 
    // Let us create a 2D table to store
    // solutions of subproblems. C[i][j]
    // will be true if C[0..i+j-1] is an
    // interleaving of A[0..i-1] and B[0..j-1].
    boolean IL[][] = new boolean[M + 1][N + 1];
 
    // IL is default initialised by false
 
    // C can be an interleaving of A and B
    // only if the sum of lengths of A and B
    // is equal to length of C
    if ((M + N) != C.length())
        return false;
 
    // Process all characters of A and B
 
    for(int i = 0; i <= M; i++)
    {
        for(int j = 0; j <= N; j++)
        {
             
            // Two empty strings have an
            // empty strings as interleaving
            if (i == 0 && j == 0)
                IL[i][j] = true;
 
            // A is empty
            else if (i == 0)
            {
                if (B.charAt(j - 1) ==
                    C.charAt(j - 1))
                    IL[i][j] = IL[i][j - 1];
             }
 
            // B is empty
            else if (j == 0)
            {
                if (A.charAt(i - 1) ==
                    C.charAt(i - 1))
                    IL[i][j] = IL[i - 1][j];
            }
 
            // Current character of C matches
            // with current character of A,
            // but doesn't match with current
            // character if B
            else if (A.charAt(i - 1) ==
                     C.charAt(i + j - 1) &&
                     B.charAt(j - 1) !=
                     C.charAt(i + j - 1))
                IL[i][j] = IL[i - 1][j];
 
            // Current character of C matches
            // with current character of B, but
            // doesn't match with current
            // character if A
            else if (A.charAt(i - 1) !=
                     C.charAt(i + j - 1) &&
                     B.charAt(j - 1) ==
                     C.charAt(i + j - 1))
                IL[i][j] = IL[i][j - 1];
 
            // Current character of C matches
            // with that of both A and B
            else if (A.charAt(i - 1) ==
                     C.charAt(i + j - 1) &&
                     B.charAt(j - 1) ==
                     C.charAt(i + j - 1))
                IL[i][j] = (IL[i - 1][j] ||
                            IL[i][j - 1]);
         }
    }
    return IL[M][N];
}
 
// Function to run test cases
static void test(String A, String B, String C)
{
    if (isInterleaved(A, B, C))
        System.out.println(C + " is interleaved of " +
                           A + " and " + B);
    else
        System.out.println(C + " is not interleaved of " +
                           A + " and " + B);
}
 
// Driver code
public static void main(String[] args)
{
    test("XXY", "XXZ", "XXZXXXY");
    test("XY", "WZ", "WZXY");
    test("XY", "X", "XXY");
    test("YX", "X", "XXY");
    test("XXY", "XXZ", "XXXXZY");
}
}
 
// This code is contributed by th_aditi


Python3




# A Dynamic Programming based python3 program
# to check whether a string C is an interleaving
# of two other strings A and B.
 
# The main function that returns true if C is
# an interleaving of A and B, otherwise false.
def isInterleaved(A, B, C):
 
    # Find lengths of the two strings
    M = len(A)
    N = len(B)
 
    # Let us create a 2D table to store solutions of
    # subproblems. C[i][j] will be true if C[0..i + j-1]
    # is an interleaving of A[0..i-1] and B[0..j-1].
    # Initialize all values as false.
    IL = [[False] * (N + 1) for i in range(M + 1)]
 
    # C can be an interleaving of A and B only of sum
    # of lengths of A & B is equal to length of C.
    if ((M + N) != len(C)):
        return False
 
    # Process all characters of A and B
    for i in range(0, M + 1):
        for j in range(0, N + 1):
             
            # two empty strings have an empty string
            # as interleaving
            if (i == 0 and j == 0):
                IL[i][j] = True
 
            # A is empty
            elif (i == 0):
                if (B[j - 1] == C[j - 1]):
                    IL[i][j] = IL[i][j - 1]
             
            # B is empty
            elif (j == 0):
                if (A[i - 1] == C[i - 1]):
                    IL[i][j] = IL[i - 1][j]
             
            # Current character of C matches with
            # current character of A, but doesn't match
            # with current character of B
            elif (A[i - 1] == C[i + j - 1] and
                  B[j - 1] != C[i + j - 1]):
                IL[i][j] = IL[i - 1][j]
 
            # Current character of C matches with
            # current character of B, but doesn't match
            # with current character of A
            elif (A[i - 1] != C[i + j - 1] and
                  B[j - 1] == C[i + j - 1]):
                IL[i][j] = IL[i][j - 1]
 
            # Current character of C matches with
            # that of both A and B
            elif (A[i - 1] == C[i + j - 1] and
                  B[j - 1] == C[i + j - 1]):
                IL[i][j] = (IL[i - 1][j] or IL[i][j - 1])
         
    return IL[M][N]
 
# A function to run test cases
def test(A, B, C):
 
    if (isInterleaved(A, B, C)):
        print(C, "is interleaved of", A, "and", B)
    else:
        print(C, "is not interleaved of", A, "and", B)
 
# Driver Code
if __name__ == '__main__':
    test("XXY", "XXZ", "XXZXXXY")
    test("XY", "WZ", "WZXY")
    test("XY", "X", "XXY")
    test("YX", "X", "XXY")
    test("XXY", "XXZ", "XXXXZY")
     
# This code is contributed by ashutosh450


C#




// A Dynamic Programming based program 
// to check whether a string C is 
// an interleaving of two other 
// strings A and B.
using System;
class GFG
{
     
    // The main function that returns 
    // true if C is an interleaving of A 
    // and B, otherwise false.  
    static bool isInterleaved(string A, string B, 
                                 string C) 
    {
           
        // Find lengths of the two strings
        int M = A.Length, N = B.Length;
       
        // Let us create a 2D table to store
        // solutions of subproblems. C[i][j] 
        // will be true if C[0..i+j-1] is an
        // interleaving of A[0..i-1] and B[0..j-1].
        bool[ , ] IL = new bool[M + 1, N + 1];
       
        // IL is default initialised by false      
        // C can be an interleaving of A and B
        // only if the sum of lengths of A and B
        // is equal to length of C
        if ((M + N) != C.Length)
            return false;
       
        // Process all characters of A and B 
        for(int i = 0; i <= M; i++)
        {
            for(int j = 0; j <= N; j++)
            {
                   
                // Two empty strings have an
                // empty strings as interleaving
                if (i == 0 && j == 0)
                    IL[i, j] = true;
       
                // A is empty
                else if (i == 0)
                {
                    if (B[j - 1] == C[j - 1])
                        IL[i, j] = IL[i, j - 1];
                 }
       
                // B is empty
                else if (j == 0)
                {
                    if (A[i - 1] == C[i - 1])
                        IL[i, j] = IL[i - 1, j];
                }
       
                // Current character of C matches
                // with current character of A, 
                // but doesn't match with current
                // character if B
                else if (A[i - 1] == C[i + j - 1] && 
                         B[j - 1] != C[i + j - 1])
                    IL[i, j] = IL[i - 1, j];
       
                // Current character of C matches
                // with current character of B, but
                // doesn't match with current
                // character if A
                else if (A[i - 1] != C[i + j - 1] && 
                         B[j - 1] == C[i + j - 1])
                        IL[i, j] = IL[i, j - 1];
       
                // Current character of C matches
                // with that of both A and B
                else if (A[i - 1] == C[i + j - 1] && 
                         B[j - 1] == C[i + j - 1])
                       IL[i, j] = (IL[i - 1, j] || 
                                IL[i, j - 1]);
             }
        }
        return IL[M, N];
    }
       
    // Function to run test cases
    static void test(string A, string B, string C) 
    {
        if (isInterleaved(A, B, C))
            Console.WriteLine(C + " is interleaved of " +
                               A + " and " + B);
        else
            Console.WriteLine(C + " is not interleaved of " +
                               A + " and " + B);
    }  
   
  // Driver code
  static void Main()
  {
    test("XXY", "XXZ", "XXZXXXY");
    test("XY", "WZ", "WZXY");
    test("XY", "X", "XXY");
    test("YX", "X", "XXY");
    test("XXY", "XXZ", "XXXXZY");
  }
}
 
// This code is contributed by divyeshrabadiya07


Javascript




<script>
 
// A Dynamic Programming based program
// to check whether a string C is
// an interleaving of two other
// strings A and B.
 
 
// The main function that
// returns true if C is
// an interleaving of A
// and B, otherwise false.
function isInterleaved(A, B, C)
{
    // Find lengths of the two strings
    let M = A.length, N = B.length;
 
    // Let us create a 2D table
    // to store solutions of
    // subproblems.  C[i][j] will
    // be true if C[0..i+j-1]
    // is an interleaving of
    // A[0..i-1] and B[0..j-1].
    // Initialize all values as false.
    let IL = new Array(M + 1);
 
    for(let i=0;i<M+1;i++){
        IL[i] = new Array(N + 1).fill(0);
    }
 
 
    // C can be an interleaving of
    // A and B only of the sum
    // of lengths of A & B is equal
    // to the length of C.
    if ((M + N) != C.length)
        return false;
 
    // Process all characters of A and B
    for (let i = 0; i <= M; ++i) {
        for (let j = 0; j <= N; ++j) {
            // two empty strings have an
            // empty string as interleaving
            if (i == 0 && j == 0)
                IL[i][j] = true;
 
            // A is empty
            else if (i == 0) {
                if (B[j - 1] == C[j - 1])
                    IL[i][j] = IL[i][j - 1];
            }
 
            // B is empty
            else if (j == 0) {
                if (A[i - 1] == C[i - 1])
                    IL[i][j] = IL[i - 1][j];
            }
 
            // Current character of C matches
            // with current character of A,
            // but doesn't match with current
            // character of B
            else if (
                A[i - 1] == C[i + j - 1]
                && B[j - 1] != C[i + j - 1])
                IL[i][j] = IL[i - 1][j];
 
            // Current character of C matches
            // with current character of B,
            // but doesn't match with current
            // character of A
            else if (
                A[i - 1] != C[i + j - 1]
                && B[j - 1] == C[i + j - 1])
                IL[i][j] = IL[i][j - 1];
 
            // Current character of C matches
            // with that of both A and B
            else if (
                A[i - 1] == C[i + j - 1]
                && B[j - 1] == C[i + j - 1])
                IL[i][j]
                    = (IL[i - 1][j]
                       || IL[i][j - 1]);
        }
    }
 
    return IL[M][N];
}
 
// A function to run test cases
function test(A, B, C)
{
    if (isInterleaved(A, B, C))
        document.write(C + " is interleaved of " + A + " and " + B,"</br>");
    else
        document.write(C + " is not interleaved of " + A + " and " + B,"</br>");
}
 
// Driver program to test above functions
 
test("XXY", "XXZ", "XXZXXXY");
test("XY", "WZ", "WZXY");
test("XY", "X", "XXY");
test("YX", "X", "XXY");
test("XXY", "XXZ", "XXXXZY");
 
// This code is contributed by shinjanpatra
</script>


Output: 

XXZXXXY is not interleaved of XXY and XXZ
WZXY is interleaved of XY and WZ
XXY is interleaved of XY and X
XXY is not interleaved of YX and X
XXXXZY is interleaved of XXY and XXZ

See this for more test cases.
Complexity Analysis: 

  • Time Complexity: O(M*N). 
    Since a traversal of the DP array is needed, so the time complexity is O(M*N).
  • Space Complexity: O(M*N). 
    This is the space required to store the DP array.

https://youtu.be/WBXy-sztEwI 
Please write comments if you find anything incorrect, or if you want to share more information about the topic discussed above. 

Method 3: Dynamic Programming(Memoization)

Approach: We can make a matrix where rows and columns represent the characters of the string A and B. If C is the interleaved string of A and B then there exists a path from the top left of the Matrix to the bottom right. That is if we can go from index 0,0 to n,m while matching characters of all A and B with C then C is interleaved of A and B.

Let A be “XXY”, B be “XXZ” and C be “XXZXXY” then the path would look something like this:

  X X Y  
X 1 0 0 0
X 1 0 0 0
Z 1 0 0 0
  1 1 1 R

let us consider one more example, let A be “ABC”, B be “DEF” and C be “ADBECF”, then the path would look something like this:

  D E F  
A 1 0 0 0
B 1 1 0 0
C 0 1 1 0
  0 0 1 R

If there exists a path through which we can reach R, then C is the interleaved strings of A and B.

Algorithm:

1. We will first create a matrix dp to store the path since one path can be explored multiple times, the Matrix index dp[i][j] will store if there exists a path from this index or not.

2. If we are at i’th index of A and j’th index of B and C[i+j] matches both A[i] and B[j] then we explore both the paths that are we will go right and down i.e. we will explore index i+1,j and j+1,i.

3. If C[i+j] only matches with A[i] or B[j] then we will go just down or right respectively that is i+1,j or i,j+1.

C++




// A Memoization program
// to check whether a string C is
// an interleaving of two other
// strings A and B.
#include <iostream>
#include <string.h>
using namespace std;
 
// Declare n,m for storing the size of the strings.
int n, m;
 
// Declare dp array
int dp[101][101];
 
// declaration of dfs function.
bool dfs(int i, int j, string &A, string &B, string &C);
 
// The main function that
// returns true if C is
// an interleaving of A
// and B, otherwise false.
bool isInterleave(string A, string B, string C)
{
    // Strong the length in n,m
    n = A.length(), m = B.length();
 
    // C can be an interleaving of
    // A and B only of the sum
    // of lengths of A & B is equal
    // to the length of C.
    if ((n + m) != C.length())
        return 0;
   
    // initializing dp array with -1
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= m; j++)
            dp[i][j] = -1;
   
    // calling and returning the answer
    return dfs(0, 0, A, B, C);
}
 
// This function checks if there exist a valid path from 0,0 to n,m
bool dfs(int i, int j, string &A, string &B, string &C)
{
    // If path has already been calculated from this index
    // then return calculated value.
    if (dp[i][j] != -1)
        return dp[i][j];
 
    // If we reach the destination return 1
    if (i == n && j == m)
        return 1;
 
    // If C[i+j] matches with both A[i] and B[j]
    // we explore both the paths
    if (i < n && A[i] == C[i + j] && j < m && B[j] == C[i + j])
    {
        // go down and store the calculated value in x
        // and go right and store the calculated value in y.
        int x = dfs(i + 1, j, A, B, C), y = dfs(i, j + 1, A, B, C);
 
        // return the best of both.
        return dp[i][j] = x | y;
    }
 
    // If C[i+j] matches with A[i].
    if (i < n && A[i] == C[i + j])
    {
        // go down
        int x = dfs(i + 1, j, A, B, C);
 
        // Return the calculated value.
        return dp[i][j] = x;
    }
 
    // If C[i+j] matches with B[j].
    if (j < m && B[j] == C[i + j])
    {
        int y = dfs(i, j + 1, A, B, C);
       
        // Return the calculated value.
        return dp[i][j] = y;
    }
   
    // if nothing matches we return 0
    return dp[i][j] = 0;
}
 
// A function to run test cases
void test(string A, string B, string C)
{
    if (isInterleave(A, B, C))
        cout << C << " is interleaved of "
             << A << " and " << B << endl;
    else
        cout << C << " is not interleaved of "
             << A << " and " << B << endl;
}
 
// Driver program to test above functions
int main()
{
    test("XXY", "XXZ", "XXZXXXY");
    test("XY", "WZ", "WZXY");
    test("XY", "X", "XXY");
    test("YX", "X", "XXY");
    test("XXY", "XXZ", "XXXXZY");
    test("ACA", "DAS", "DAACSA");
    return 0;
}


Java




// A Java Memoization program
// to check whether a string C is
// an interleaving of two other
// strings A and B.
 
import java.io.*;
 
class GFG {
 
    // Declare n,m for storing the size of the strings.
    static int n, m;
 
    // Declare dp array
    static int dp[][] = new int[100][100];
 
    // declaration of dfs function.
    // This function checks if there exist a valid path from
    // 0,0 to n,m
    public static int dfs(int i, int j, String A, String B,
                          String C)
    {
        // If path has already been calculated from this
        // index then return calculated value.
        if (dp[i][j] != -1)
            return dp[i][j];
 
        // If we reach the destination return 1
        if (i == n && j == m)
            return 1;
 
        // If C[i+j] matches with both A[i] and B[j]
        // we explore both the paths
        if (i < n && A.charAt(i) == C.charAt(i + j) && j < m
            && B.charAt(j) == C.charAt(i + j)) {
            // go down and store the calculated value in x
            // and go right and store the calculated value
            // in y.
            int x = dfs(i + 1, j, A, B, C),
                y = dfs(i, j + 1, A, B, C);
 
            // return the best of both.
            return dp[i][j] = x | y;
        }
 
        // If C[i+j] matches with A[i].
        if (i < n && A.charAt(i) == C.charAt(i + j)) {
            // go down
            int x = dfs(i + 1, j, A, B, C);
 
            // Return the calculated value.
            return dp[i][j] = x;
        }
 
        // If C[i+j] matches with B[j].
        if (j < m && B.charAt(j) == C.charAt(i + j)) {
            int y = dfs(i, j + 1, A, B, C);
 
            // Return the calculated value.
            return dp[i][j] = y;
        }
 
        // if nothing matches we return 0
        return dp[i][j] = 0;
    }
 
    // The main function that
    // returns true if C is
    // an interleaving of A
    // and B, otherwise false.
    public static int isInterleave(String A, String B,
                                   String C)
    {
        // Strong the length in n,m
        n = A.length();
        m = B.length();
 
        // C can be an interleaving of
        // A and B only of the sum
        // of lengths of A & B is equal
        // to the length of C.
        if ((n + m) != C.length())
            return 0;
 
        // initializing dp array with -1
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= m; j++)
                dp[i][j] = -1;
 
        // calling and returning the answer
        return dfs(0, 0, A, B, C);
    }
 
    // A function to run test cases
    public static void test(String A, String B, String C)
    {
        if (isInterleave(A, B, C) != 0)
            System.out.println(C + " is interleaved of " + A
                               + " and " + B);
        else
            System.out.println(C + " is not interleaved of "
                               + A + " and " + B);
    }
 
    // Driver program to test above functions
    public static void main(String[] args)
    {
        test("XXY", "XXZ", "XXZXXXY");
        test("XY", "WZ", "WZXY");
        test("XY", "X", "XXY");
        test("YX", "X", "XXY");
        test("XXY", "XXZ", "XXXXZY");
        test("ACA", "DAS", "DAACSA");
    }
}
 
// This code is contributed by Rohit Pradhan


Python3




# A Python Memoization program
# to check whether a string C is
# an interleaving of two other
# strings A and B.
 
# Declare dp array
dp = [[0]*101]*101
 
# This function checks if there exist a valid path from 0,0 to n,m
def dfs(i, j, A, B, C):
 
    # If path has already been calculated from this index
    # then return calculated value.
    if(dp[i][j]!=-1):
        return dp[i][j]
         
    # If we reach the destination return 1
    n,m=len(A),len(B)
    if(i==n and j==m):
        return 1
     
    # If C[i+j] matches with both A[i] and B[j]
    # we explore both the paths
     
    if (i<n and A[i]==C[i + j] and j<m and B[j]==C[i + j]):
        # go down and store the calculated value in x
        # and go right and store the calculated value in y.
        x = dfs(i + 1, j, A, B, C)
        y = dfs(i, j + 1, A, B, C)
         
        # return the best of both.
        dp[i][j] = x|y
        return dp[i][j]
     
    # If C[i+j] matches with A[i].
    if (i < n and A[i] == C[i + j]):
        # go down
        x = dfs(i + 1, j, A, B, C)
         
        # Return the calculated value.
        dp[i][j] = x
        return dp[i][j]
     
    # If C[i+j] matches with B[j].
    if (j < m and B[j] == C[i + j]):
        y = dfs(i, j + 1, A, B, C)
         
        # Return the calculated value.
        dp[i][j] = y
        return dp[i][j]
     
    # if nothing matches we return 0
    dp[i][j] = 0
    return dp[i][j]
 
# The main function that
# returns true if C is
# an interleaving of A
# and B, otherwise false.
def isInterleaved(A, B, C):
 
    # Storing the length in n,m
    n = len(A)
    m = len(B)
     
    # C can be an interleaving of
    # A and B only of the sum
    # of lengths of A & B is equal
    # to the length of C.
     
    if((n+m)!=len(C)):
        return 0
     
    # initializing dp array with -1
    for i in range(n+1):
        for j in range(m+1):
            dp[i][j]=-1
     
    # calling and returning the answer
    return dfs(0,0,A,B,C)
     
 
# A function to run test cases
def test(A, B, C):
 
    if (isInterleaved(A, B, C)):
        print(C, "is interleaved of", A, "and", B)
    else:
        print(C, "is not interleaved of", A, "and", B)
 
# Driver Code
if __name__ == '__main__':
    test("XXY", "XXZ", "XXZXXXY")
    test("XY", "WZ", "WZXY")
    test("XY", "X", "XXY")
    test("YX", "X", "XXY")
    test("XXY", "XXZ", "XXXXZY")
    test("ACA", "DAS", "DAACSA")
     
# This code is contributed by Pushpesh Raj.


C#




using System;
using System.Linq;
 
class GFG {
 
    // Declare n,m for storing the size of the strings.
    static int n, m;
 
    // Declare dp array
    static int[, ] dp = new int[100, 100];
 
    // declaration of dfs function.
    // This function checks if there exist a valid path from
    // 0,0 to n,m
    public static int dfs(int i, int j, string A, string B,
                          string C)
    {
        // If path has already been calculated from this
        // index then return calculated value.
        if (dp[i, j] != -1)
            return dp[i, j];
 
        // If we reach the destination return 1
        if (i == n && j == m)
            return 1;
 
        // If C[i+j] matches with both A[i] and B[j]
        // we explore both the paths
        if (i < n && A[i] == C[i + j] && j < m
            && B[j] == C[i + j]) {
            // go down and store the calculated value in x
            // and go right and store the calculated value
            // in y.
            int x = dfs(i + 1, j, A, B, C),
                y = dfs(i, j + 1, A, B, C);
 
            // return the best of both.
            return dp[i, j] = x | y;
        }
 
        // If C[i+j] matches with A[i].
        if (i < n && A[i] == C[i + j]) {
            // go down
            int x = dfs(i + 1, j, A, B, C);
 
            // Return the calculated value.
            return dp[i, j] = x;
        }
 
        // If C[i+j] matches with B[j].
        if (j < m && B[j] == C[i + j]) {
            int y = dfs(i, j + 1, A, B, C);
 
            // Return the calculated value.
            return dp[i, j] = y;
        }
 
        // if nothing matches we return 0
        return dp[i, j] = 0;
    }
 
    // The main function that
    // returns true if C is
    // an interleaving of A
    // and B, otherwise false.
    public static int isInterleave(string A, string B,
                                   string C)
    {
        // Strong the length in n,m
        n = A.Length;
        m = B.Length;
 
        // C can be an interleaving of
        // A and B only of the sum
        // of lengths of A & B is equal
        // to the length of C.
        if ((n + m) != C.Length)
            return 0;
 
        // initializing dp array with -1
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= m; j++)
                dp[i, j] = -1;
 
        // calling and returning the answer
        return dfs(0, 0, A, B, C);
    }
    // A function to run test cases
    public static void test(string A, string B, string C)
    {
        if (isInterleave(A, B, C)==1)
            Console.WriteLine(C + " is interleaved of " + A
                              + " and " + B);
        else
            Console.WriteLine(C + " is not interleaved of "
                              + A + " and " + B);
    }
 
    // Driver program to test above functions
    public static void Main(string[] args)
    {
        test("XXY", "XXZ", "XXZXXXY");
    test("XY", "WZ", "WZXY");
    test("XY", "X", "XXY");
    test("YX", "X", "XXY");
    test("XXY", "XXZ", "XXXXZY");
    test("ACA", "DAS", "DAACSA");
    }
}


Javascript




// Declaration of the variables n and m to store the length of the strings A and B
let n, m;
 
// Declaration of dp array
let dp = [];
 
// Function to check if string C is an interleaving of A and B
function isInterleave(A, B, C) {
  // Store the length of the strings A and B in n and m
  n = A.length;
  m = B.length;
 
  // If the sum of the lengths of A and B is not equal to the length of C,
  // return false as C cannot be an interleaving of A and B
  if (n + m !== C.length) {
    return false;
  }
 
  // Initialize dp array with -1
  for (let i = 0; i <= n; i++) {
    dp[i] = [];
    for (let j = 0; j <= m; j++) {
      dp[i][j] = -1;
    }
  }
 
  // Return the result of calling dfs function
  return dfs(0, 0, A, B, C);
}
 
// Function to check if there exist a valid path from (i, j) to (n, m)
function dfs(i, j, A, B, C) {
  // If path has already been calculated from this index,
  // return the calculated value
  if (dp[i][j] !== -1) {
    return dp[i][j];
  }
 
  // If (i, j) reaches (n, m), return true
  if (i === n && j === m) {
    return true;
  }
 
  // If C[i+j] matches with both A[i] and B[j],
  // explore both paths and return the best of both
  if (i < n && A[i] === C[i + j] && j < m && B[j] === C[i + j]) {
    let x = dfs(i + 1, j, A, B, C);
    let y = dfs(i, j + 1, A, B, C);
    dp[i][j] = x || y;
    return dp[i][j];
  }
 
  // If C[i+j] matches with A[i], go down and return the calculated value
  if (i < n && A[i] === C[i + j]) {
    let x = dfs(i + 1, j, A, B, C);
    dp[i][j] = x;
    return dp[i][j];
  }
 
  // If C[i+j] matches with B[j], go right and return the calculated value
  if (j < m && B[j] === C[i + j]) {
    let y = dfs(i, j + 1, A, B, C);
    dp[i][j] = y;
    return dp[i][j];
  }
 
  // If C[i+j] doesn't match with either A[i] or B[j], return false
  dp[i][j] = false;
  return dp[i][j];
}
 
// Function to run test cases
function test(A, B, C) {
if (isInterleave(A, B, C)) {
console.log(C + " is interleaved of " + A + " and " + B);
} else {
console.log(C + " is not interleaved of " + A + " and " + B);
}
}
 
// Driver function to test above functions
function main() {
test("XXY", "XXZ", "XXZXXXY");
test("XY", "WZ", "WZXY");
test("XY", "X", "XXY");
test("YX", "X", "XXY");
test("XXY", "XXZ", "XXXXZY");
test("ACA", "DAS", "DAACSA");
}
 
// Call the main function
main();


Output

XXZXXXY is not interleaved of XXY and XXZ
WZXY is interleaved of XY and WZ
XXY is interleaved of XY and X
XXY is not interleaved of YX and X
XXXXZY is interleaved of XXY and XXZ
DAACSA is interleaved of ACA and DAS

Complexity Analysis:

Time Complexity:  O(m*n).

This is the worst case of time complexity, if the given strings contain no common character matching with C then the time complexity will be O(n+m).
Space Complexity: O(m*n).

This is the space required to store the DP array.

The above method and implementation are contributed by Anirudh Singh.

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments