线性动态规划:交错字符串
字数 1861 2025-10-28 08:36:45
线性动态规划:交错字符串
题目描述
给定三个字符串 s1、s2 和 s3,请判断 s3 是否能由 s1 和 s2 交错组成。交错指的是在保持 s1 和 s2 中每个字符相对顺序不变的前提下,将它们穿插合并成一个新字符串。例如:
- 输入:
s1 = "aabcc",s2 = "dbbca",s3 = "aadbbcbcac" - 输出:
true(因为s3可以拆分为"aa"(来自 s1) +"dbbc"(来自 s2) +"bc"(来自 s1) +"a"(来自 s2) +"c"(来自 s1),且各部分顺序不变)
解题思路
- 问题分析:若直接尝试所有交错方式会指数级复杂。动态规划通过记录子问题结果避免重复计算。
- 状态定义:设
dp[i][j]表示s1的前i个字符和s2的前j个字符能否交错组成s3的前i+j个字符。 - 状态转移:
- 若
s1[i-1] == s3[i+j-1],则dp[i][j]取决于dp[i-1][j](即前一步由s1提供字符)。 - 若
s2[j-1] == s3[i+j-1],则dp[i][j]也取决于dp[i][j-1](即前一步由s2提供字符)。 - 综上:
dp[i][j] = (dp[i-1][j] && s1[i-1]==s3[i+j-1]) || (dp[i][j-1] && s2[j-1]==s3[i+j-1])。
- 若
- 边界条件:
dp[0][0] = true(空字符串可组成空字符串)。- 第一行
dp[0][j]:仅当s2的前j字符完全匹配s3的前j字符时为true。 - 第一列
dp[i][0]:类似,仅由s1匹配s3的前i字符。
详细步骤
- 初始化:创建
(len(s1)+1) x (len(s2)+1)的二维数组dp,全部初始化为false。 - 处理边界:
dp[0][0] = true。- 遍历
j从 1 到len(s2),若s2[j-1] == s3[j-1]且dp[0][j-1]为真,则dp[0][j] = true。 - 遍历
i从 1 到len(s1),若s1[i-1] == s3[i-1]且dp[i-1][0]为真,则dp[i][0] = true。
- 填充动态规划表:
- 双重循环遍历
i从 1 到len(s1),j从 1 到len(s2):- 计算
k = i+j-1(s3中当前检查的位置)。 - 若
s1[i-1] == s3[k]且dp[i-1][j]为真,则dp[i][j] = true。 - 否则若
s2[j-1] == s3[k]且dp[i][j-1]为真,则dp[i][j] = true。
- 计算
- 双重循环遍历
- 返回结果:最终结果为
dp[len(s1)][len(s2)]。
示例验证
以 s1="aab", s2="dbb", s3="aadbbb" 为例:
- 初始化后,第一行
dp[0][1](s2="d"匹配s3="a"?)为false,第一列dp[1][0](s1="a"匹配s3="a")为true。 - 计算
dp[1][1]:k=1,s1[0]='a'匹配s3[1]='a'?否(实际s3[1]='a'但s1[0]已用于dp[1][0],需结合位置:此处应比较s3[i+j-1]即s3[1]与s1[0]和s2[0])。- 修正:
k=i+j-1=1+1-1=1,s3[1]是第二个字符(索引从0开始),即'a'。但s1[0]='a'匹配,且dp[0][1]为假;s2[0]='d'不匹配,因此dp[1][1]=false。
- 继续填充直至
dp[3][3],最终检查是否匹配整个s3。
复杂度分析
- 时间复杂度:O(mn),其中 m 和 n 分别为
s1和s2的长度。 - 空间复杂度:可优化至 O(min(m,n)),但基础版本为 O(mn)。