c++ string取子串_Go 刷 LeetCode 系列:动态规划(2)最长公共子串(子序列)

子串(Substring)是串的一个连续的部分,子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列;更简略地说,前者(子串)的字符的位置必须连续,后者(子序列 LCS)则不必。比如字符串 acdfg 同 akdfc 的最长公共子串为 df,而他们的最长公共子序列是 adf。

最长公共子串

假设已知 s1[0:i-1],s2[0:j-1]从右往左数的最长公共子串长度,那么两字符串同时右移一位,如果 s1[i]==s2[j],则 s1[0:i],s2[0:j]在 i,j 位置的最长公共子串长度是 s1[0:i-1],s2[0:j-1]从右往左数的最长公共子串长度+ 1,否则是 0,用 a[i][j]记录此长度,状态转移方程如下:

if s1[i] == s2[j] {
a[i][j] = a[i-1][j-1]+1
} else {
a[i][j] = 0
}

用到了 i-1,j-1, 所以两个都递增,初始化都为 0,如果两个首字母相同 a[0][0:j]=1,a[0:i][0]=1

func Lcs(s1 string, s2 string) string {
if len(s1) == 0 || len(s2) == 0 {
return ""
}
a := make([][]int, len(s1))
for i := 0; i < len(s1); i++ {
a[i] = make([]int, len(s2))
if []byte(s1)[i] == []byte(s2)[0] {
a[i][0] = 1
}
}
for j := 1; j < len(s2); j++ {
if []byte(s1)[0] == []byte(s2)[j] {
a[0][j] = 1
}
}
max := 0
ii := 0
jj := 0
for i := 1; i < len(s1); i++ {
for j := 1; j < len(s2); j++ {
if []byte(s1)[i] == []byte(s2)[j] {
a[i][j] = a[i-1][j-1] + 1
}
if a[i][j] > max {
max = a[i][j]
ii = i
jj = j
}
}
}
return string([]byte(s1)[ii+1-a[ii][jj] : ii+1])
}

最长公共子序列

假设已知 s1[0:i-1],s2[0:j-1]的最长公共子序列,如果 s1[i]==s2[j],则,s1[0:i],s2[0:j]的长度为 s1[0:i-1],s2[0:j-1]的最长公共子序列+ 1,否则取 s1[0:i],s2[0:j-1] 与 s1[0:i-1],s2[0:j]中的大者,同 a[i][j]记录最长公共子序列的长度,状态转移方程为:

if s1[i]==s2[j]{
a[i][j]=a[i-1][j-1]+1
} else {
a[i][j]=max(a[]i)[j-1],a[i-1][j])
}

用到了 i-1,j-1,所以两个都递增,初始化都为 0,如果两个首字母相同 a[0][0:j]=1,a[0:i][0]=1

func Lcs(s1 string, s2 string) int {
if len(s1) == 0 || len(s2) == 0 {
return 0
}
a := make([][]int, len(s1))
for i := 0; i < len(s1); i++ {
a[i] = make([]int, len(s2))
if []byte(s1)[i] == []byte(s2)[0] {
a[i][0] = 1
}
}
for j := 1; j < len(s2); j++ {
if []byte(s1)[0] == []byte(s2)[j] {
a[0][j] = 1
}
}
max := 0
for i := 1; i < len(s1); i++ {
for j := 1; j < len(s2); j++ {
if []byte(s1)[i] == []byte(s2)[j] {
a[i][j] = a[i-1][j-1] + 1
} else if a[i][j-1] > a[i-1][j] {
a[i][j] = a[i][j-1]
} else {
a[i][j] = a[i-1][j]
}
if a[i][j] > max {
max = a[i][j]
}
}
}
return max
}

推荐阅读

  • Go 刷 LeetCode 系列:动态规划(1)最长回文子串


喜欢本文的朋友,欢迎关注“Go语言中文网”:

700a56980475639c9b712b5872e95d89.png

Go语言中文网启用微信学习交流群,欢迎加微信:274768166

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值