字符串的动态规划问题

参考内容

处理两个字符串的动态规划问题

一般来说,处理字符串的动态规划问题,可以借鉴参考下面这张图:

在这里插入图片描述
第一步,一定要明确 dp 数组的含义。对于两个字符串的动态规划问题,套路是通用的。比如说对于字符串 s1 和 s2,一般来说都要构造一个这样的 DP table:
在这里插入图片描述

LeetCode72 编辑距离

编辑距离>>>
参考题解>>>在这里插入图片描述
解决两个字符串的动态规划问题,一般都是用两个指针i,j分别指向两个字符串的最后,然后一步步往前走,缩小问题的规模

在这里插入图片描述
在这里插入图片描述


package com.zj.FDynamicProgramming.taolu;

/**
 * @Author Zhou Jian
 * @Date 2020/8/9
 * 编辑距离
 */
public class Problem72 {
    /**
     * @param word1
     * @param word2
     * @return
     * s1--->s2
     * s2走完,s1没走完将s1缩短为s2
     * if s1[i] == s2[j]:
     *     啥都别做(skip)
     *     i, j 同时向前移动
     * else:
     *     三选一:
     *         插入(insert)
     *         删除(delete)
     *         替换(replace)
     *
     *  有这个框架,问题就已经解决了。读者也许会问,这个「三选一」到底该怎么选择呢?
     *  很简单,全试一遍,哪个操作最后得到的编辑距离最小,就选谁。这里需要递归技巧,理解需要点技巧,先看下代
     *  dp[i][j]  s1[0,,,,,i] 到s2[0.....j]的最小编辑距离
     *  dp[0][j] = j
     *  dp[i][0] = i
     *  dp[i][j] = min(dp[i-1][j]+1,dp[i-1][j-1]+1 ,dp[i][j-1]+1)
     *  有了之前递归解法的铺垫,应该很容易理解。dp[..][0] 和 dp[0][..] 对应 base case,dp[i][j] 的含义和之前的 dp 函数类似:
     */
    public int minDistance(String word1, String word2) {
        if(word1==null&&word2==null) return 0;
        if(word1.length()==0&&word2.length()==0) return 0;
        int[][] dp = new int[word1.length()+1][word2.length()+1];
        for(int j=0;j<=word1.length();j++) dp[j][0] = j;
        for(int i=0;i<=word2.length();i++) dp[0][i]= i;
        for(int i=1;i<=word1.length();i++){
            for(int j=1;j<=word2.length();j++){
                // 相等则不需要操作
                if(word1.charAt(i)==word2.charAt(j)) {
                    dp[i][j] = dp[i-1][j-1];
                    continue;
                }
                // 若不等则从增加,删除,修改中选择一个最小的
                dp[i][j] = Math.min(dp[i-1][j]+1,dp[i][j-1]+1);
                dp[i][j] = Math.min(dp[i][j],dp[i-1][j-1]+1);
            }
        }
        return dp[word1.length()][word2.length()];
    }
}



LeetCode1143 两个字符串最长公共子序列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


package com.zj.FDynamicProgramming.taolu;

/**
 * @Author Zhou Jian
 * @Date 2020/8/9
 */
public class Problem1143 {

    /**
     *
     * @param text1
     * @param text2
     * @return
     *
     * dp[i][j]  两个字符串中 s1[0...i] s2[0.....j]的最长公共子序列
     * dp[0][j] = 0  dp[i][0] = 0
     *
     * if(s1[i]==s2[j]) dp[i][j] = dp[i-1][j-1]+1
     * dp[i][j] = max(dp[i-1][j-1]
     *                  dp[i-1][j]
     *                  dp[i][j-1])
     *
     *最长公共子序列(Longest Common Subsequence,简称 LCS)是一道非常经典的面试题目,因为它的解法是典型的二维动态规划,
     *大部分比较困难的字符串问题都和这个问题一个套路,比如说编辑距离。而且,这个算法稍加改造就可以用于解决其他问题,
     *所以说 LCS 算法是值得掌握的。
     *
     * 肯定有读者会问,为啥这个问题就是动态规划来解决呢?因为子序列类型的问题,穷举出所有可能的结果都不容易
     * ,而动态规划算法做的就是穷举 + 剪枝,它俩天生一对儿。所以可以说只要涉及子序列问题,十有八九都需要动态规划来解决,往这方面考虑就对了。
     */
    public int longestCommonSubsequence(String text1, String text2) {
        if(text1==null||text2==null) return 0;
        if(text1.length()==0||text2.length()==0) return 0;

        int[][] dp = new int[text1.length()+1][text2.length()+1];
        for(int i=0;i<text1.length()+1;i++) dp[i][0] = 0;
        for(int j=0;j<text2.length()+1;j++) dp[0][j] = 0;

        for(int i=1;i<dp.length;i++){
            for(int j=1;j<dp[0].length;j++){
                // 若两个字符相等则从 dp[i][j]  text1中前i个字符 与 text2中前j个字符的最长公共子序列
                if(text1.charAt(i-1)==text2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+1;
                    continue;
                }
                // 字符串s1[0..i] s2[0j]最长公共子序列的长度
                //  s1删除一个 或者 s2删除一个 或者两个都删除
                dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
                dp[i][j] = Math.max(dp[i][j],dp[i-1][j-1]);
            }
        }
        return dp[text1.length()][text2.length()];
    }



}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值