题目描述
给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。
两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:
s = s1 + s2 + … + sn
t = t1 + t2 + … + tm
|n - m| <= 1
交错 是 s1 + t1 + s2 + t2 + s3 + t3 + … 或者 t1 + s1 + t2 + s2 + t3 + s3 + …
注意:a + b 意味着字符串 a 和 b 连接。
示例 1:
输入:s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出:true
思路分析
动规题。
1.确定dp数组含义:
dp[i][j] 表示s1前i个字符和s2前j个字符能否构成s3的前i+j个字符。
2.分析递推公式:
由于需要s1+s2来构成s3,所以设想子问题s3的最后一个字符是由谁构成的。
- 若s3的最后一个字符由s1提供,则有:s3[i+j] = s1[i],而 s3 此前的 i+j−1个字符,可由 s1 的前 i−1 字符和 s2 的前 j 个字符共同提供。这时候就要去判断dp数组的上一个状态了,即若 dp[i−1][j]为真,则 dp[i][j]为真。
- 若s3最后一个字符由s2提供,则同理
if s1[i-1] == s3[i+j-1] and dp[i-1][j]:
dp[i][j] = True
if s2[j-1] == s3[i+j-1] and dp[i][j-1]:
dp[i][j] = True
别忘了 dp[i][j] 表示s1前i个字符(不包含i)
3.初始化
由于为了方便,所以数组都从下标1开始。
在初始化的时候 多开一行一列的dp数组。
必有:dp [0][0] = True。
dp的第二行和第二列也需要初始化,就直接比较当前s1或者s2字符和当前的s3字符是否相等,如果相等,看看前一个dp位置是否也是True,如果是则当前dp位置也是True。
for i in range(1, n + 1):
dp [i][0] = dp [i - 1][0] and s1[i - 1] == s3[i - 1]
for i in range(1, m + 1):
dp [0][i] = dp [0][i - 1] and s2[i - 1] == s3[i - 1]
完整代码
class Solution:
def isInterleave(self, s1: str, s2: str, s3: str) -> bool:
# dp[i][j] 表示s1前i个字符和s2前j个字符能否构成s3的前i+j个字符
n, m, l = len(s1), len(s2), len(s3)
if n + m != l:
return False
dp = [[False] * (m + 1) for _ in range(n + 1)]
dp [0][0] = True
for i in range(1, n + 1):
dp [i][0] = dp [i - 1][0] and s1[i - 1] == s3[i - 1]
for i in range(1, m + 1):
dp [0][i] = dp [0][i - 1] and s2[i - 1] == s3[i - 1]
for i in range(1,n+1):
for j in range(1,m+1):
if s1[i-1] == s3[i+j-1] and dp[i-1][j]:
dp[i][j] = True
if s2[j-1] == s3[i+j-1] and dp[i][j-1]:
dp[i][j] = True
return dp[-1][-1]```