最长公共子序列问题

最近在leetcode上碰到了一个要求用最少的步数删除某些字符最终使得两个字符串一样的问题,原问题如下:
Given two words word1 and word2, find the minimum number of steps required to make word1 and word2 the same, where in each step you can delete one character in either string.

Example 1:
Input: “sea”, “eat”
Output: 2
Explanation: You need one step to make “sea” to “ea” and another step to make “eat” to “ea”.
后来发现这个问题就是算法导论动态规划中的最长公共子序列问题,当时对于最长公共子序列的理解不深,现在再来回归下。
给定序列 X=<x1,x2,x3,x4,...,xn> , 另一个序列Z = <z1,z2,....,zk> <script type="math/tex" id="MathJax-Element-7830"> </script>, 如果存在一个严格递增的序列X的下标序列为 <i1,i2,...,ik> <script type="math/tex" id="MathJax-Element-7831"> </script>,对所有j = 1, 2, 3 …, k,满足 Xij=Zj ,则称Z为X的一个子序列。
最长公共子序列问题:对序列X和Y,如果存在一个序列Z使得Z是X和Y的子序列,且是最长的,则称Z为X和Y的最长子序列LCS(longest common subsequence)。
最长公共子序列具有这样的性质:令X = <x1,x2,x3,x4...,xm> <script type="math/tex" id="MathJax-Element-7833"> </script>, Y = <y1,y2,y3,...yn> <script type="math/tex" id="MathJax-Element-7834"> </script>为两个序列,Z = <z1,z2,...zk> <script type="math/tex" id="MathJax-Element-7835"> </script>为X和Y的任意LCS。
1. 如果 xm=yn 那么 zk=xm=yn , 且 zk1 xm1 yn1 的LCS。
2. 如果 xmyn ,若 zkxm 意味着Z是 xm1 和Y的一个LCS。
3. 如果 xmyn ,若 zkyn$Z y_{n-1}$和X的一个LCS。

这个性质说明两个序列的LCS包含两个序列的前缀的LCS。也就是说我们可以通过求出它的前缀的子问题从而来求解原问题。
c[i,j] 表示 Xi Yj 两个序列的LCS的长度,显然如果i = 0或者j = 0,即一个序列长度为0,则最长公共子序列也为0,C[i, j] = 0,根据LCS性质,可得如下公式:

c[i,j]=0,c[i1,j1]+1,max(c[i1,j],c[i,j1]),if i == 0 or j == 0if xi == yjif xiyj

有了这个公式我们就可以开始写代码了,用一个二维数组记录c[i,j]记录 Xi Yj 两序列的LCS,通过对记录子问题的解来得到原问题的解。

public class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length();
        int n = word2.length();
        int[][] c = new int[m+1][n+1];
        for(int i = 0; i <= m; i++){
            c[i][0] = 0;
        }
        for(int j = 0; j <= n; j++){
            c[0][j] = 0;
        }

        for(int i = 1; i <= m ;i++){
            for(int j = 1; j <= n; j++){
                if(word1.charAt(i-1) == word2.charAt(j-1)){
                    c[i][j] = c[i-1][j-1] + 1;
                }else{
                    if(c[i-1][j] > c[i][j-1]){
                        c[i][j] = c[i-1][j];
                    }else{
                        c[i][j] = c[i][j-1];
                    }
                }
            }
        }
        return m + n - 2*c[m][n];
    }
}

通过计算两个字符串的LCS, 然后使用两个字符串的长度和减去LCS的两倍,即可得到最小步数。
代码时间复杂度为 O(mn) ,空间复杂度为 O(mn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值