区间动态规划例题:最小窗口子序列问题
字数 1174 2025-11-06 12:40:04

区间动态规划例题:最小窗口子序列问题

题目描述
给定字符串 S 和 T,找出 S 中最短的子串(连续子序列),使得 T 是该子串的子序列。如果不存在这样的子串,返回空字符串。如果有多个长度相同的最短子串,返回最左边的一个。

示例

  • S = "abcdebdde", T = "bde"
  • 答案:"bcde"(包含子序列 "bde",且比 "bdde" 更短)

解题思路
这个问题可以通过区间动态规划解决,但更高效的方法是使用双指针或动态规划记录匹配位置。我将采用基于动态规划的"最后出现位置"方法,它本质上是区间DP思想的变种。

详细解题步骤

步骤1:定义状态

  • 定义 dp[i][j] 表示在 S 的前 i 个字符中匹配 T 的前 j 个字符时,匹配序列的起始位置。
  • 更准确地说,dp[i][j] 表示使得 S[k:i] 包含 T[1:j] 作为子序列的最大起始位置 k。

步骤2:状态转移方程

  1. 当 S[i] = T[j] 时:

    • 如果 j = 1,那么匹配可以从位置 i 开始,即 dp[i][1] = i
    • 如果 j > 1,那么我们需要在 i 之前找到匹配 T[1:j-1] 的位置,即 dp[i][j] = dp[i-1][j-1]
  2. 当 S[i] ≠ T[j] 时:

    • 当前字符不匹配,起始位置继承自前一个位置,即 dp[i][j] = dp[i-1][j]

步骤3:初始化

  • dp[0][j] = -1(空字符串无法匹配非空T)
  • dp[i][0] = i(匹配空字符串的起始位置为i)

步骤4:寻找最优解
遍历整个S字符串,当匹配完成时(j = len(T)),计算当前窗口长度:

  • 窗口长度 = i - dp[i][len(T)] + 1
    记录最小窗口及其起始位置。

具体执行过程

以 S = "abcdebdde", T = "bde" 为例:

  1. 初始化dp表(i从1开始,j从1开始):

    • 第一行和第一列按规则初始化
  2. 逐个填充dp表:

    • i=1, j=1: S[1]='a'≠'b', dp[1][1]=dp[0][1]=-1
    • i=2, j=1: S[2]='b'='b', dp[2][1]=2
    • i=3, j=2: S[3]='c'≠'d', dp[3][2]=dp[2][2]=-1
    • ...
    • 当匹配完成时记录窗口
  3. 最终找到最小窗口为"bcde"(起始位置2,长度4)

算法优化
实际实现时可以使用滚动数组优化空间复杂度,从O(mn)降到O(n)。

复杂度分析

  • 时间复杂度:O(mn),其中m为T长度,n为S长度
  • 空间复杂度:O(n)(优化后)

这种方法确保了找到最短且最左边的满足条件的子串,是区间动态规划在字符串匹配中的典型应用。

区间动态规划例题:最小窗口子序列问题 题目描述 给定字符串 S 和 T,找出 S 中最短的子串(连续子序列),使得 T 是该子串的子序列。如果不存在这样的子串,返回空字符串。如果有多个长度相同的最短子串,返回最左边的一个。 示例 S = "abcdebdde", T = "bde" 答案:"bcde"(包含子序列 "bde",且比 "bdde" 更短) 解题思路 这个问题可以通过区间动态规划解决,但更高效的方法是使用双指针或动态规划记录匹配位置。我将采用基于动态规划的"最后出现位置"方法,它本质上是区间DP思想的变种。 详细解题步骤 步骤1:定义状态 定义 dp[ i][ j ] 表示在 S 的前 i 个字符中匹配 T 的前 j 个字符时,匹配序列的起始位置。 更准确地说,dp[ i][ j] 表示使得 S[ k:i] 包含 T[ 1:j ] 作为子序列的最大起始位置 k。 步骤2:状态转移方程 当 S[ i] = T[ j ] 时: 如果 j = 1,那么匹配可以从位置 i 开始,即 dp[ i][ 1 ] = i 如果 j > 1,那么我们需要在 i 之前找到匹配 T[ 1:j-1] 的位置,即 dp[ i][ j] = dp[ i-1][ j-1 ] 当 S[ i] ≠ T[ j ] 时: 当前字符不匹配,起始位置继承自前一个位置,即 dp[ i][ j] = dp[ i-1][ j ] 步骤3:初始化 dp[ 0][ j ] = -1(空字符串无法匹配非空T) dp[ i][ 0 ] = i(匹配空字符串的起始位置为i) 步骤4:寻找最优解 遍历整个S字符串,当匹配完成时(j = len(T)),计算当前窗口长度: 窗口长度 = i - dp[ i][ len(T) ] + 1 记录最小窗口及其起始位置。 具体执行过程 以 S = "abcdebdde", T = "bde" 为例: 初始化dp表(i从1开始,j从1开始): 第一行和第一列按规则初始化 逐个填充dp表: i=1, j=1: S[ 1]='a'≠'b', dp[ 1][ 1]=dp[ 0][ 1 ]=-1 i=2, j=1: S[ 2]='b'='b', dp[ 2][ 1 ]=2 i=3, j=2: S[ 3]='c'≠'d', dp[ 3][ 2]=dp[ 2][ 2 ]=-1 ... 当匹配完成时记录窗口 最终找到最小窗口为"bcde"(起始位置2,长度4) 算法优化 实际实现时可以使用滚动数组优化空间复杂度,从O(mn)降到O(n)。 复杂度分析 时间复杂度:O(mn),其中m为T长度,n为S长度 空间复杂度:O(n)(优化后) 这种方法确保了找到最短且最左边的满足条件的子串,是区间动态规划在字符串匹配中的典型应用。