Interleaving String
Question
- leetcode: Interleaving String | LeetCode OJ
- lintcode: (29) Interleaving String
Given three strings: s1, s2, s3,
determine whether s3 is formed by the interleaving of s1 and s2.
Example
For s1 = "aabcc", s2 = "dbbca"
When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.
Challenge
O(n2) time or better
题解3 - 动态规划
看过题解1 和 题解2 的思路后动规的状态和状态方程应该就不难推出了。按照经典的序列规划,不妨假设状态 f[i1][i2][i3] 为 s1的前i1个字符和 s2的前 i2个字符是否能交叉构成 s3的前 i3个字符,那么根据 s1[i1], s2[i2], s3[i3]的匹配情况可以分为8种情况讨论。咋一看这似乎十分麻烦,但实际上我们注意到其实还有一个隐含条件:len3 == len1 + len2
, 故状态转移方程得到大幅简化。
新的状态可定义为 f[i1][i2], 含义为s1的前i1
个字符和 s2的前 i2
个字符是否能交叉构成 s3的前 i1 + i2
个字符。根据 s1[i1] == s3[i3]
和 s2[i2] == s3[i3]
的匹配情况可建立状态转移方程为:
f[i1][i2] = (s1[i1 - 1] == s3[i1 + i2 - 1] && f[i1 - 1][i2]) ||
(s2[i2 - 1] == s3[i1 + i2 - 1] && f[i1][i2 - 1])
这道题的初始化有点 trick, 考虑到空串的可能,需要单独初始化 f[*][0]
和 f[0][*]
.
Python
class Solution:
"""
@params s1, s2, s3: Three strings as description.
@return: return True if s3 is formed by the interleaving of
s1 and s2 or False if not.
@hint: you can use [[True] * m for i in range (n)] to allocate a n*m matrix.
"""
def isInterleave(self, s1, s2, s3):
len1 = 0 if s1 is None else len(s1)
len2 = 0 if s2 is None else len(s2)
len3 = 0 if s3 is None else len(s3)
if len3 != len1 + len2:
return False
f = [[True] * (1 + len2) for i in xrange (1 + len1)]
# s1[i1 - 1] == s3[i1 + i2 - 1] && f[i1 - 1][i2]
for i in xrange(1, 1 + len1):
f[i][0] = s1[i - 1] == s3[i - 1] and f[i - 1][0]
# s2[i2 - 1] == s3[i1 + i2 - 1] && f[i1][i2 - 1]
for i in xrange(1, 1 + len2):
f[0][i] = s2[i - 1] == s3[i - 1] and f[0][i - 1]
# i1 >= 1, i2 >= 1
for i1 in xrange(1, 1 + len1):
for i2 in xrange(1, 1 + len2):
case1 = s1[i1 - 1] == s3[i1 + i2 - 1] and f[i1 - 1][i2]
case2 = s2[i2 - 1] == s3[i1 + i2 - 1] and f[i1][i2 - 1]
f[i1][i2] = case1 or case2
return f[len1][len2]
class Solution:
# @return a boolean
def isInterleave(self, s1, s2, s3):
if len(s1)+len(s2)!=len(s3): return False
dp=[[False for i in range(len(s2)+1)] for j in range(len(s1)+1)]
dp[0][0]=True
for i in range(1,len(s1)+1):
dp[i][0] = dp[i-1][0] and s3[i-1]==s1[i-1]
for i in range(1,len(s2)+1):
dp[0][i] = dp[0][i-1] and s3[i-1]==s2[i-1]
for i in range(1,len(s1)+1):
for j in range(1,len(s2)+1):
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[len(s1)][len(s2)]
源码分析
为后面递推方便,初始化时数组长度多加1,for 循环时需要注意边界(取到等号)。
复杂度分析
双重 for 循环,时间复杂度为 $$O(n^2)$$, 使用了二维矩阵,空间复杂度 $$O(n^2)$$. 其中空间复杂度可以优化。
Reference
- soulmachine 的 Interleaving String 部分
- Interleaving String 参考程序 Java/C++/Python