算法细节系列(14):动态规划之字符串处理

来源:互联网 发布:淘宝能买哪些虚拟产品 编辑:程序博客网 时间:2024/05/21 22:10

算法细节系列(14):动态规划之字符串处理

详细代码可以fork下Github上leetcode项目,不定期更新。

题目均摘自leetcode:

  • 392 Is Subsequence
  • 516 Longest Palindromic Subsequence
  • 072 Edit Distance

392.Is Subsequence

水题,不一定要使用DP,但既然此章节关于DP,咱们就用DP解。

    public boolean isSubsequence(String s, String t){        if (s.isEmpty()) return true;        int n = s.length();        boolean[] isSeq = new boolean[n];        int index = 0;        for (int i = 0; i < t.length(); i++){            if (s.charAt(index) == t.charAt(i)){                isSeq[index++] = true;                if (isSeq[n-1]) return true;            }        }        return isSeq[n-1];    }

516. Longest Palindromic Subsequence

一道区间DP,更新没什么好说的,但需要注意两个for循环的遍历顺序。递推式:

//dp[j][i] 表示在区间[j,i]之间的最长回文,可断s[j] == s[i]: dp[j][i] = dp[j+1][i-1] + 2;//没有最新的回文生成,所以沿用旧的回文长度s[j] != s[i]: dp[j][i] = Math.max(dp[j+1][i],dp[j][i-1]);
public int longestPalindromeSubseq(String s) {        int n = s.length();        int[][] dp = new int[n][n];        char[] c = s.toCharArray();        for (int i = 0; i < n; i++) {            dp[i][i] = 1;            for (int j = i-1; j >= 0; j--) {                if (c[j] == c[i]) {                    dp[j][i] = dp[j + 1][i - 1] + 2;                } else {                    dp[j][i] = Math.max(dp[j+1][i], dp[j][i-1]);                }            }        }        return dp[0][n-1];    }

72. Edit Distance

比较抽象的一道题,要求两个字符串的最短编辑距离。

dp[i][j] : 表示word1[0,i)和word2[0,j)的最短编辑距离如:dp[1][0] = 1, "a"," "dp[1][1] = ?, "a","a" 相等,? = 0"a","b" 不相等, ? = 1初始化:(字符串为空串的情况下,最短编辑距离等于字符串长度)dp[i][0] = i;dp[0][j] = j;递推式:dp[i][j] = dp[i-1][j-1];  if word1[i] == word2[j];dp[i][j] = min(dp[i-1][j] + dp[i][j-1] + dp[i-1][j-1]) + 1; if word1[i] != word2[j];举个简单的例子说明它们的含义:(word1不去操作,所有操作在word2上进行)word1 : "a"word2 : "ab"dp[0][0] = 0; " " == " "dp[0][1] = 1; edit -> "&a", "&b"dp[0][2] = 2; edit -> "&&a", "&&"dp[1][1] = dp[0][0] = 0; "a" == "a", no editdp[1][2] = ?; "a" != "b"存在三种情况:a. dp[1][2] = dp[0][1] = 2; "&a","&b" edit -> "&a","&a"我们已知道了dp[0][1]表示为"&a","&b",所以只能进行替换操作。即:dp[i][j] = dp[i-1][j-1]dp[i-1][j-1]表示了最短编辑距离,也可以表示成两字符串经过编辑后已然相等,而此时为了能够更新到dp[i][j],只能对word2的第j个字符做替换操作。b. dp[1][2] = dp[1][1] = 1; "a","ab" edit -> "a","a"即:dp[i][j] = dp[i][j-1]显然,dp[1][1] = 0,没有操作。而此时为了能够更新到dp[i][j],让两字符串相等,只能删除word2的第j个字符。c. dp[1][2] = dp[0][2] = 3; "&&a","&&" edit -> "&&a","&&a"即:dp[i][j] = dp[i-1][j];同理,dp[0][2] = 2, 说明了word2 = "&&",而为了能够更新到dp[i][j],只能添加到第j个字符后。最后在这三种操作中,取最小的即可。

注意:”&”空字符串占位符,所以有”&&” = “&”,且我们所有操作只针对一个对象。代码如下:

    public int minDistance(String word1, String word2) {        int m = word1.length();        int n = word2.length();        int[][] cost = new int[m + 1][n + 1];        for (int i = 0; i <= m; i++)            cost[i][0] = i;        for (int i = 1; i <= n; i++)            cost[0][i] = i;        for (int i = 0; i < m; i++) {            for (int j = 0; j < n; j++) {                if (word1.charAt(i) == word2.charAt(j))                    cost[i + 1][j + 1] = cost[i][j];                else {                    int a = cost[i][j];                    int b = cost[i][j + 1];                    int c = cost[i + 1][j];                    cost[i + 1][j + 1] = a < b ? (a < c ? a : c) : (b < c ? b : c);                    cost[i + 1][j + 1]++;                }            }        }        return cost[m][n];    }
0 0
原创粉丝点击