This is a question from The Algorithm Design Manual:
Suppose you are given three strings of characters:
X
,Y
, andZ
, where|X| = n
,|Y| = m
, and|Z| = n+m.
Z
is said to be a shuffle ofX
andY
if and only ifZ
can be formed by interleaving the characters fromX
andY
in a way that maintains the left-to right ordering of the characters from each string.Give an efficient dynamic programming algorithm that determines whether
Z
is a shuffle ofX
andY
.Hint: the values of the dynamic programming matrix you construct should be Boolean, not numeric
This is what I tried:
Initially, I made a 1-D char array and pointers to the starting characters of X,Y,Z respectively. If Z-pointer with matches X-pointer store X in the char array else check the same with Y-pointer.If each entry in the char array is not different from its last entry, Z is not interleaved.
Can someone help me with this problem?
First, let's start with some definitions. I write X[i]
for the i
th element of X
and X[i)
for the substring of X
starting at index i
.
For example, if X = abcde
, then X[2] = c
and X[2) = cde
.
Similar definitions hold for Y
and Z
.
To solve the problem by dynamic programming, you should keep a 2D boolean array A
of size (n+1) x (m+1)
. In this array, A[i, j] = true
if and only if X[i)
and Y[j)
can be interleaved to form Z[i+j)
.
For an arbitrary (i, j)
, somewhere in the middle of the 2D array, the recurrence relation is very simple:
A[i, j] := X[i] = Z[i+j] and A[i+1, j]
or Y[j] = Z[i+j] and A[i, j+1]
On the edges of the 2D array you have the case that either X
or Y
is already at its end, which means the suffix of the other should be equal to the suffix of Z
:
A[m, j] := Y[j) = Z[m+j)
A[i, n] := X[i) = Z[i+n)
A[m, n] := true
If you first fill the border of the array (A[m, j]
and A[i, n]
, for all i, j
), you can then simply loop back towards A[0, 0]
and set the entries appropriately. In the end A[0, 0]
is your answer.
Following approach should give you an idea.
Define the condition d(s1,s2,s3) = (s1 + s2 == s3) { s3 is a shuffle of s1 and s2 }
We have to find d( X, Y, Z )
.
if lengths of s1 and s2 are 1 each and length of s3 = 2,
d( s1,s2,s3 ) = { (s1[0] == s3[0] && s2[0] == s3[1]) || (s1[0] == s3[1] && s2[0] == s3[0])
Similarly d can be obtained for empty strings.
For strings of arbitrary length, following relation holds.
d( s1,s2,s3 ) = { ( d( s1-s1[last],s2,s3 - s3[last]) && s1[last] == s3[last] )
|| ( d( s1,s2 - s2[last],s3 - s3[last]) && s2[last] == s3[last] )
}
You can compute the d()
entries starting from zero length strings and keep checking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With