算法复习——动态规划篇之最长公共子串问题

算法复习——动态规划篇之最长公共子串问题

以下内容主要参考中国大学MOOC《算法设计与分析》,墙裂推荐希望入门算法的童鞋学习!

1. 问题背景

子串:给定序列中零个或多个连续的元素(如字符)组成的子序列

公共子串

  • 给定两个序列 X X X Y Y Y

    在这里插入图片描述

  • 公共子串示例

    在这里插入图片描述

​ 问题是如何求两个给定序列的最长公共子串?

2. 问题定义

最长公共子串问题(Longest Common Substring Problem)

输入:

  • 序列 X = < x 1 , x 2 , … , x n > X=<x_1, x_2, \dots, x_n> X=<x1,x2,,xn>和序列 Y = < y 1 , y 2 , … , y m > Y=<y_1, y_2, \dots, y_m> Y=<y1,y2,,ym>

输出:

  • 求解一个公共子串 Z = < z 1 , z 2 , … , z l > Z=<z_{1}, z_{2}, \dots, z_{l}> Z=<z1,z2,,zl>,令 m a x ∣ Z ∣ max|Z| maxZ

    s . t . Z = < x i , x i + 1 , … , x i + l − 1 > = < y j , y j + 1 , … , y j + l − 1 > s.t. Z=<x_i, x_{i+1}, \dots, x_{i+l-1}>=<y_j, y_{j+1}, \dots, y_{j+l-1}> s.t.Z=<xi,xi+1,,xi+l1>=<yj,yj+1,,yj+l1>

    ( 1 ≤ i ≤ n − l + 1 ; 1 ≤ j ≤ m − l + 1 ) (1 \leq i \leq n-l+1;1 \leq j \leq m-l+1) (1inl+1;1jml+1)

3. 动态规划

3.1 问题结构分析

  • 给出问题表示:

    • C [ i , j ] C[i,j] C[i,j] X [ 1.. i ] X[1..i] X[1..i] Y [ 1.. j ] Y[1..j] Y[1..j]中, x i x_i xi y j y_j yj结尾的最长公共子串 Z [ 1.. l ] Z[1..l] Z[1..l]的长度

在这里插入图片描述

  • 明确原始问题:

    • p m a x = m a x 1 ≤ i ≤ n , 1 ≤ j ≤ m { C [ i , j ] } p_{max}=max_{1 \leq i \leq n, 1\leq j \leq m}\{C[i,j]\} pmax=max1in,1jm{C[i,j]}
      • X [ 1.. n ] X[1..n] X[1..n] Y [ 1.. m ] Y[1..m] Y[1..m]中最长公共子串的长度

3.2 递推关系建立

3.2.1 分析最优(子)结构
  • 情况1: x i ≠ y j x_i \neq y_j xi=yj

    C [ i , j ] = 0 C[i,j]=0 C[i,j]=0,因为不存在以 x i x_i xi y j y_j yj结尾的公共子串,无子问题

  • 情况2: x i = y j x_i = y_j xi=yj

    C [ i , j ] = C [ i − 1 , j − 1 ] + 1 C[i, j] = C[i-1, j-1] + 1 C[i,j]=C[i1,j1]+1

3.2.2 构造递推公式

C [ i , j ] = { 0 , x i ≠ y j C [ i − 1 , j − 1 ] + 1 , x i = y j C[i,j]=\left\{ \begin{array}{rcl} 0, & & {x_i \neq y_j}\\ C[i-1,j-1]+1, & & {x_i = y_j}\\ \end{array} \right. C[i,j]={0,C[i1,j1]+1,xi=yjxi=yj

3.3 自底向上计算

3.3.1 确定计算顺序
  • 初始化: C [ i , 0 ] = C [ 0 , j ] = 0 C[i, 0]=C[0, j]=0 C[i,0]=C[0,j]=0(某序列长度为0时,最长公共子串为0)

  • 递推公式:
    C [ i , j ] = { 0 , x i ≠ y j C [ i − 1 , j − 1 ] + 1 , x i = y j C[i,j]=\left\{ \begin{array}{rcl} 0, & & {x_i \neq y_j}\\ C[i-1,j-1]+1, & & {x_i = y_j}\\ \end{array} \right. C[i,j]={0,C[i1,j1]+1,xi=yjxi=yj
    在这里插入图片描述

3.3.2 依次求解问题

在这里插入图片描述

3.4 最优方案追踪

  • 记录决策过程
    • 最长公共子串末尾位置为 p m a x p_{max} pmax
    • 最长公共子串长度为 l m a x l_{max} lmax
  • 输出最优方案
    • 最长公共子串 < x p m a x − l + 1 , x p m a x − l + 2 , … , x p m a x > <x_{p_{max}-l+1}, x_{p_{max}-l+2}, \dots, x_{p_{max}}> <xpmaxl+1,xpmaxl+2,,xpmax>

4. 伪代码

Longest-Common-Substring(X, Y)

输入:两个字符串X,Y

输出:X和Y的最长公共子串

// 初始化
n ← length(X)
m ← length(Y)
新建二维数组C[0..n, 0..m]
l_max ← 0
p_max ← 0
for i ← 0 to n do
	C[i, 0] ← 0
end
for j ← 0 to m do
	C[0, j] ← 0
end
// 动态规划
for i ← 1 to n do
	for j ← 1 to m do
		if X[i] != Y[j] then
			C[i, j] ← 0
		end
		else
			C[i, j] ← C[i-1, j-1] + 1
			if C[i, j] > l_max then
				l_max ← C[i, j]
				p_max ← i
			end
		end
	end
end

Print-LCS(X, l_max, p_max)

输入:字符串X,l_max,p_max

输出:X和Y的最长公共子串

if l_max = 0 then
	return NULL
end
if i ← (p_max - l_max + 1) to p_max do
	print X[i]
end

​ 该算法的时间复杂度是 O ( m n ) O(mn) O(mn)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值