美文网首页
最长公共子序列

最长公共子序列

作者: 追风骚年 | 来源:发表于2021-01-29 23:26 被阅读0次

最长公共子序列(Longest Common Subsequence,简称 LCS)是非常经典的动态规划题目。
通常有两种方式,一个是自顶向下的递归写法,一个是自底向上的 dp table 写法,这里我在使用递归时,发现 golang 的一个问题,如果在函数内部定义个函数,那么内部函数的内部是无法访问到内部函数名。

例如:

func lcs(s1, s2 string) {
    dp := func(i, j int) int {
         ...
        return dp(i, j-1) // 这里是无法访问到 dp 函数名
    }
}

由于 golang 的严谨性,函数在使用的过程中,必须先定义,所以如下修改:

func lcs(s1, s2 string) {
    var dp func(i, j int) int
    dp = func(i, j int) int {
        // ...
        return dp(i, j-1) // success 
    }
}

虽然看起来有点蹩脚,但是只有这样才能通过编译。通过声明和赋值放一起,这样固然是舒服和便携,但编译器都是先执行等号右边再去赋值给左边,在右边的函数内部,还并不知道左边的变量名。

LCS 完整代码

  • 递归版本
func lcs(text1, text2 string) int {
    cache := make([][]int, len(text1))

    for idx := range cache {
        cache[idx] = make([]int, len(text2))
    }

    var dp func(i, j int) int

    dp = func(i, j int) int {

        if i == -1 {
            return 0
        }

        if j == -1 {
            return 0
        }

        if cache[i][j] != 0 {
            return cache[i][j]
        }

        if text1[i] == text2[j] {
            cache[i][j] = dp(i-1, j-1) + 1
        } else {
            d1 := dp(i, j-1)
            d2 := dp(i-1, j)

            if d1 > d2 {
                cache[i][j] = d1
            } else {
                cache[i][j] = d2
            }
        }

        return cache[i][j]
    }
    return dp(len(text1)-1, len(text2)-1)
}

这里也取了一个巧,将 i,j == -1 的判断放上面,因为如果先走 cache 的话,就可能遇到越界的操作了。

  • 打表版本
func lcs(text1, text2 string) int {
    m, n := len(text1), len(text2)
    dp := make([][]int, m+1)

    for idx := range dp {
        dp[idx] = make([]int, n+1)
    }

    for i := 1; i <= m; i++ {
        for j := 1; j <= n; j++ {
            if text1[i-1] == text2[j-1] {
                dp[i][j] = dp[i-1][j-1] + 1
            } else {
                dp[i][j] = max(dp[i][j-1], dp[i-1][j])
            }
        }
    }
    return dp[m][n]
}

func max(n1, n2 int) int {
    if n1 > n2 {
        return n1
    }
    return n2
}

这里不得不吐槽一下 math 包中的 max 函数居然是 float64 类型的,实际应用中反而 int 类型用途更广。

相关文章

  • 公共子序列问题

    最长公共子序列 最长上升子序列 最长公共上升子序列

  • 最长公共子序列和最长公共子串

    最长公共子序列和最长公共子串区别 最长公共子串(Longest CommonSubstring)和最长公共子序列(...

  • 算法(04)动态规划

    零钱问题 背包问题 最长公共子序列 最长公共子串 最长上升子序列 最大连续子序列和

  • LCS问题

    LCS问题包括最长公共子序列和最长公共子串,其中,最长公共子串要求必须连续。 对于二者的求解方式 最长公共子序列:...

  • 子序列问题

    最长公共子序列 最长上升/下降/不升/不降子序列

  • 子串 子序列 总结

    最长公共子串 子串的要求比子序列严格,所以可以讨论子串的终点 最长公共子序列 DP解 递归+memo 最长公共回文...

  • 序列比对(二十四)——最长公共子序列

    原创:hxj7 本文介绍如何求解两个字符串的最长公共子序列。 最长公共子序列问题 前文《序列比对(23)最长公共子...

  • lintcode 最长公共子序列

    给出两个字符串,找到最长公共子序列(LCS),返回LCS的长度。说明最长公共子序列的定义: 最长公共子序列问题是在...

  • 字符串的几个问题

    1.最长公共子序列2.最长公共子串3.最长回文串4.最长回文序列5.最长递增序列6.最长先增后减序列7.(最短)编...

  • 算法问题清单

    最大子序列和最长公共子序列最长公共子串大整数相乘/除/加数组最大乘积

网友评论

      本文标题:最长公共子序列

      本文链接:https://www.haomeiwen.com/subject/zzactltx.html