问题描述:
给定三个字符串 s1
, s2
, s3
, 验证 s3
是否是由 s1
和 s2
交错组成的。
示例 1:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出: true
示例 2:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出: false
问题分析:
这个题目类似于115. Distinct Subsequences 或者有共同的解法。
先理解一下题目,验证 s3
是否是由 s1
和 s2
交错组成的,也就是说,s3
是不是有这两个字符串相互交织组成,而且这两个字符串各用 1 次,不是多次哦。
题目已经给了提示,动态规划方法,现在就分析一下,先找一下问题的最优子结构:
(1)最优子结构或者子问题,s3
是不是由s1
和s2
相互交织组成是一个大问题,s3[1, n-1]
是不是由s1[1, m-1]
和s2
,或者s1
和s2[1, m-1]
相互交织组成,现在是不是从大问题中,一步一步向下找到子问题了?(假设字符串从1开始计算)
(2)设dp[i][j]
表示s3[0:i+j]
是否可以由s1[0:i]
和s2[0:j]
交织组成,现在看看如何求得dp[i][j]
的值?很显然,有两个路径可以到达这个位置,即,从dp[i-1][j]
的位置,然后判断s1[i-1] == s3[i+j-1]
,也就是让s1[i-1]
作为s3[0: i+j]
最后一个字符。同理也可以从dp[i][j-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])
(3) 以 s1, s2, s3 = "aabcc", "dbbca", "aadbbcbcac"
为例,看看dp
的变化图:
(图片来自官方解答,下面已经给出链接)
Python3实现:
# @Time :2019/02/05
# @Author :LiuYinxing
# 动态规划
class Solution:
def isInterleave(self, s1, s2, s3):
"""
:type s1: str
:type s2: str
:type s3: str
:rtype: bool
"""
if len(s3) != len(s1) + len(s2):
return False
dp = [[None] * (len(s2) + 1) for _ in range(len(s1)+1)] # 初始化dp
for i in range(len(s1)+1):
for j in range(len(s2)+1):
if i == 0 and j == 0:
dp[i][j] = True
elif i == 0: # 计算上边界
dp[i][j] = dp[i][j-1] and s2[j-1] == s3[i+j-1]
elif j == 0: # 计算下边界
dp[i][j] = dp[i-1][j] and s1[i-1] == s3[i+j-1]
else: # 从两个方向向左下角计算
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[-1][-1]
if __name__ == '__main__':
solu = Solution()
s1, s2, s3 = "aabcc", "dbbca", "aadbbcbcac"
print(solu.isInterleave(s1, s2, s3))
空间压缩:,从上面的图片不难看出,我们一行一行的计算,所有的计算都是相邻行的计算,所以我们可以把空间压缩到一维,只保留一行。代码如下:
# @Time :2019/02/05
# @Author :LiuYinxing
# 动态规划
class Solution:
def isInterleave(self, s1, s2, s3):
"""
:type s1: str
:type s2: str
:type s3: str
:rtype: bool
"""
if len(s3) != len(s1) + len(s2):
return False
dp = [None] * (len(s2) + 1) # 初始化dp
for i in range(len(s1)+1):
for j in range(len(s2)+1):
if i == 0 and j == 0:
dp[j] = True
elif i == 0: # 计算上边界
dp[j] = dp[j-1] and s2[j-1] == s3[i+j-1]
elif j == 0: # 计算下边界
dp[j] = dp[j] and s1[i-1] == s3[i+j-1]
else: # 从两个方向向左下角计算
dp[j] = (dp[j] and s1[i-1] == s3[i+j-1]) or (dp[j-1] and s2[j-1] == s3[i+j-1])
return dp[-1]
if __name__ == '__main__':
solu = Solution()
s1, s2, s3 = "aabcc", "dbbca", "aadbbcbcac"
print(solu.isInterleave(s1, s2, s3))
声明: 总结学习,有问题或不当之处,可以批评指正哦,谢谢。