m, n, and p, write a method to find out if p has been formed by interleaving m and n. p would be considered interleaving m and n if it contains all the letters from m and n and the order of letters is preserved too.Example 1
Input: m="abd", n="cef", p="adcbef"
Output: false
Explanation: 'p' contains all the letters from 'm' and 'n' but does not preserve the order. Example 2
Input: m="abc", n="def", p="abdccf"
Output: false
Explanation: 'p' does not contain all the letters from 'm' and 'n'. Example 3
Input: m="abcdef", n="mnop", p="mnaobcdepf"
Output: true
Explanation: 'p' contains all the letters from 'm' and 'n' and preserves their order too. The problem follows the Longest Common Subsequence (LCS) pattern and has some similarities with Subsequence Pattern Matching.
A basic brute-force solution could be to try matching m and n with p one letter at a time. Letβ s assume mIndex, nIndex, and pIndex represent the current indexes of m, n, and p strings respectively. Therefore, we have two options at any step:
If the letter at mIndex matches with the letter at pIndex, we can recursively match for the remaining lengths of m and p. If the letter at nIndex matches with the letter at βpIndexβ, we can recursively match for the remaining lengths of n and p.
Here is the code:
def find_SI(m, n, p):
return find_SI_recursive(m, n, p, 0, 0, 0)
def find_SI_recursive(m, n, p, mIndex, nIndex, pIndex):
mLen, nLen, pLen = len(m), len(n), len(p)
# if we have reached the end of the all the strings
if mIndex == mLen and nIndex == nLen and pIndex == pLen:
return True
# if we have reached the end of 'p' but 'm' or 'n' still has some characters left
if pIndex == pLen:
return False
b1, b2 = False, False
if mIndex < mLen and m[mIndex] == p[pIndex]:
b1 = find_SI_recursive(m, n, p, mIndex+1, nIndex, pIndex+1)
if nIndex < nLen and n[nIndex] == p[pIndex]:
b2 = find_SI_recursive(m, n, p, mIndex, nIndex+1, pIndex+1)
return b1 or b2
def main():
print(find_SI("abd", "cef", "abcdef"))
print(find_SI("abd", "cef", "adcbef"))
print(find_SI("abc", "def", "abdccf"))
print(find_SI("abcdef", "mnop", "mnaobcdepf"))
main() This problem can have overlapping subproblems only when there are some common letters between m and n at the same index. Because whenever we hit such a scenario, we get an option to match with any one of them.
The three changing values in our recursive function are the three indexes mIndex, nIndex, and pIndex. Therefore, we can store the results of all the subproblems in a three-dimensional array. Alternately, we can use a hash-table whose key would be a string (mIndex + β|β + nIndex + β|β + pIndex).
Here is the code for Top-down DP approach:
def find_SI(m, n, p):
return find_SI_recursive({}, m, n, p, 0, 0, 0)
def find_SI_recursive(dp, m, n, p, mIndex, nIndex, pIndex):
mLen, nLen, pLen = len(m), len(n), len(p)
# if we have reached the end of the all the strings
if mIndex == mLen and nIndex == nLen and pIndex == pLen:
return True
# if we have reached the end of 'p' but 'm' or 'n' still has some characters left
if pIndex == pLen:
return False
subProblemKey = str(mIndex) + "-" + str(nIndex) + "-" + str(pIndex)
if subProblemKey not in dp:
b1, b2 = False, False
if mIndex < mLen and m[mIndex] == p[pIndex]:
b1 = find_SI_recursive(dp, m, n, p, mIndex + 1, nIndex, pIndex + 1)
if nIndex < nLen and n[nIndex] == p[pIndex]:
b2 = find_SI_recursive(dp, m, n, p, mIndex, nIndex + 1, pIndex + 1)
dp[subProblemKey] = b1 or b2
return dp.get(subProblemKey)
def main():
print(find_SI("abd", "cef", "abcdef"))
print(find_SI("abd", "cef", "adcbef"))
print(find_SI("abc", "def", "abdccf"))
print(find_SI("abcdef", "mnop", "mnaobcdepf"))
main() Since we want to completely match m and n (the two interleaving strings) with p, we can use a two-dimensional array to store our results. The lengths of m and n will define the dimensions of the result array.
As mentioned above, we will be tracking separate indexes for m, n and p, so we will have the following options for every value of mIndex, nIndex, and pIndex:
If the character m[mIndex] matches the character p[pIndex], we will take the matching result up to mIndex-1 and nIndex.
If the character n[nIndex] matches the character p[pIndex], we will take the matching result up to mIndex and nIndex-1.
String p will be interleaving strings m and n if any of the above two options is true. This is also required as there could be some common letters between m and n.
So our recursive formula would look like:
dp[mIndex][nIndex] = false
if m[mIndex] == p[pIndex]
dp[mIndex][nIndex] = dp[mIndex-1][nIndex]
if n[nIndex] == p[pIndex]
dp[mIndex][nIndex] |= dp[mIndex][nIndex-1] Letβs draw this visually:

Here is the code for our bottom-up dynamic programming approach:
def find_SI(m, n, p):
mLen, nLen, pLen = len(m), len(n), len(p)
# dp[mIndex][nIndex] will be storing the result of string interleaving
# up to p[0..mIndex+nIndex-1]
dp = [[False for _ in range(nLen+1)] for _ in range(mLen+1)]
# make sure if lengths of the strings add up
if mLen + nLen != pLen:
return False
for mIndex in range(mLen+1):
for nIndex in range(nLen+1):
# if 'm' and 'n' are empty, then 'p' must have been empty too.
if mIndex == 0 and nIndex == 0:
dp[mIndex][nIndex] = True
# if 'm' is empty, we need to check the interleaving with 'n' only
elif mIndex == 0 and n[nIndex - 1] == p[mIndex + nIndex - 1]:
dp[mIndex][nIndex] = dp[mIndex][nIndex - 1]
# if 'n' is empty, we need to check the interleaving with 'm' only
elif nIndex == 0 and m[mIndex - 1] == p[mIndex + nIndex - 1]:
dp[mIndex][nIndex] = dp[mIndex - 1][nIndex]
else:
# if the letter of 'm' and 'p' match, we take whatever is matched till mIndex-1
if mIndex > 0 and m[mIndex - 1] == p[mIndex + nIndex - 1]:
dp[mIndex][nIndex] = dp[mIndex - 1][nIndex]
# if the letter of 'n' and 'p' match, we take whatever is matched till nIndex-1 too
# note the '|=', this is required when we have common letters
if nIndex > 0 and n[nIndex - 1] == p[mIndex + nIndex - 1]:
dp[mIndex][nIndex] |= dp[mIndex][nIndex - 1]
return dp[mLen][nLen]
def main():
print(find_SI("abd", "cef", "abcdef"))
print(find_SI("abd", "cef", "adcbef"))
print(find_SI("abc", "def", "abdccf"))
print(find_SI("abcdef", "mnop", "mnaobcdepf"))
main()