最后更新于
最后更新于
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例 1:
示例 2:
容易想到递归的思路, 如果s3
是由s1
, s2
交错组成的, 那么s3 - 1
肯定是由s1 - 1
, s2
或s1
, s2 - 1
交错组成的. 由此得到动态规划的状态为长串是否由两个短串交错组成的, 相应的状态转移方程也得到了.
使用一个二维数组来记录状态. 两个维度长度分别是s1
和s2
字符串的长度, dp[i][j]
代表是否是由s1[:i+1]
和s2[:j+1]
交错组成的.
然后考虑边际. 首先加上限制条件, s1
, s2
的长度之和必须等于s3
的长度, 否则肯定不匹配, 不加也会使得推断过程中索引越界. 满足长度限制后, 要考虑边际中s3
的前缀完全是由s1
或s2
中某一个的前缀组成的, 即另一个字符串没有任何元素参数, 这就要考虑空串交叉的情况, 因此dp
的两个维度大小都要加上1, 考虑空串.
首先dp[0][0]=True
, 这是空串肯定是由两个空串交错组成的. 然后考虑dp[i][0]
和dp[0][j]
的边际状态. 明显应该分别遍历s1
, s2
, 将前缀匹配的位置对应dp
的位置置为True
, 直到遇到第一个不匹配的字符, 包括此位置在内的, 之后的所有边际位置都不匹配, 保持False
.
既然可以递归, 那么DFS思路肯定也是可以的. 当s3[:i+j]
与s1[:i]
, s2[:j]
匹配时, 我们接下来要搜索的就是s3[:i+j+1]
与s1[:i+]
, s2[:j]
以及s3[:i+j+1]
与s1[:i]
, s2[:j+1]
是否匹配, 然后继续向下递归. 停止条件是i
和j
都超出了边界, 说明整体都是OK的.
可以预见到, 在此DFS过程中肯定会遇到大量的重复计算, 如果有多条路可以找到s3[:i+j]
与s1[:i]
, s2[:j]
这个位置, 则这个位置之后相同的搜索, 肯定会重复多次. 因此有必要加入记忆化, 判断此位置是否已经到达过, 如果到达过, 就可以剪枝了.
记忆化可以用二维数组, 或者用哈希表来实现.
代码如下:
其实此题中BFS与DFS思路很接近, 只是一个用递归, 一个用栈, 利用栈的特性.
整体代码如下. 时间复杂度和空间复杂度都为. 空间复杂度可以利用滚动数组优化到, 这是因为我们求dp[i][j]
只会用到dp[i-1][j]
和dp[i][j-1]
, 即只会使用上一行或上一列的状态, 按行或按列滚动即可.