LeetCode使用动态规划解决字符串的问题

LeetCode5 最长回文子串

最长回文子串
在这里插入图片描述
参考内容
本题使用的方法是动态规划,这里需要找的是最长回文子串,首先第一步,我们需要定义dp数组的含义,定义二维布尔数组dp[i][j]dp[i][j]数组表示:

  • 字符串s[i...j]是否为回文子串,如果是,dp[i][j]=true,如果不是dp[i][j]=false

  • 在这里插入图片描述

  • 如何我们现在已经知道了dp[i+1][j-1]dp[i+1][j−1]了,那我们如何计算dp[i][j]dp[i][j]呢?通过观察,我们发现:

    • 若s[i]==s[j]那么只要说明dp[i+1][j-1]是回文串,那么dp[i][j]也就是回文串

    • 如果s[i]\ne s[j]s[i] =s[j]那么说明dp[i][j]dp[i][j]必定不是回文子串

package com.zj.IString;

import com.zj.CLinkedList.Problem2;

/**
 * @Author Zhou Jian
 * @Date 2020/8/17
 * 组UI擦好难过回文子串
 */
public class Problem5 {

    /**
     *  动态规划
     *          dp[i][j]  i--j内回文子串的长度
     *            dp[i][j] = dp[i+1][j-1]+2
     *                       dp[i][j-1],dp[i+1][j]
     *              dp[i][i]=1
     *              i>j 0
     *
     * @param s
     * @return
     * https://leetcode-cn.com/problems/longest-palindromic-substring/solution/5-zui-chang-hui-wen-zi-chuan-dong-tai-gui-hua-jie-/
     */
    public String longestPalindrome(String s) {

        if(s==null) return "";
        if(s.length()<2) return s;
        // i,j子串是否为回文子串
        boolean[][] dp = new boolean[s.length()][s.length()];
        // 记录最长回文子串的长度
        int max = 0;
        // 记录最长回文子串的歧视以及结束位置
        int left = 0;
        int right = 0;
        for(int i =0;i<s.length();i++) dp[i][i] =true;

        for(int i= s.length()-1;i>=0;i--){
            for(int j=i+1;j<s.length();j++){
                // 遍历两边相等,则需要
                if(s.charAt(i)==s.charAt(j)) {
                    // j和i相邻的时候
                    if(j - i == 1){
                        dp[i][j] = true;
                    }
                    else{
                        dp[i][j] = dp[i+1][j-1];
                    }
                }
                else {
                   dp[i][j] = false;
                }
                if((dp[i][j])&&(j-i+1>max)){
                    max = j-i+1;
                    left = i;
                    right = j;
                }
            }
        }
        return s.substring(left,right+1);
    }

    public static void main(String[] args) {
        String s = "cbbd";
        Problem5 problem5 = new Problem5();
        String s1 = problem5.longestPalindrome(s);
        System.out.println(s1);
    }
}


LeetCode72编辑距离(两个字符串)

字符串编辑距离>>>
在这里插入图片描述

  • dp[i][j] 字符串s[0…i]转换为字符串s[0…j]所需要最少的编辑次数
  • 若s[i]==s[j]则不需要编辑,dp[i][j] = dp[i-1][j-1],否则需要进行修改增加,删除修改

package com.zj.IString;

/**
 * @Author zhoujian
 * @Date 2020/8/20 11:06
    编辑距离
 */
public class Problem72 {


    /**
     * 编辑距离:
     *  给你两个单词word1和word2,计算出将word1转换位word2所使用的最少操作数
     * @param word1
     * @param word2
     * @return
     *
     * dp[i][j]字符串s1[0..i]转换位字符串s2[0...j]所需要的最少的编辑
            dp[i][j] =  dp[i-1][j-1]
                        dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+1
                         将i添加       删除         修改一个数
    实是楼上说的 思考过程形成 = 做过类似的题😂。。。这种两个字符串的,以两个字符串分别作为二维数组的横轴和纵轴,从(0, 0)开始到(len1,len2)模拟一遍二维数组的递推,会很有助于理解~

     */
    public int minDistance(String word1, String word2) {

        int[][] dp = new int[word1.length()+1][word2.length()+1];
        for(int i=0;i<dp.length;i++) dp[i][0] = i;
        for(int i=0;i<dp[0].length;i++) dp[0][i] = i;

        for(int i=1;i<dp.length;i++){
            for (int j=0;j<dp[0].length;j++){
            		// 若字符串相等则dp[i][j]=dp[i-1][j-1]
                    if(word1.charAt(i)==word2.charAt(j)){
                        dp[i][j] = dp[i-1][j-1];
                    }else{
                        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()];
    }



}




LeetCode583 两个字符串的删除操作

链接
在这里插入图片描述

  • 转换为两个字符串中的最长公共子序列**

  • dp[i][j]为两个字符串中前s[0…i]与s2[0…j最长公共子序列长度,若s1[i]==s2[j]则dp[i][j]=dp[i-1][j-1]+1否则dp[i][j]=dp[i-1][j],dp[i][j-1]


package com.zj.IString;

/**
 * @Author zhoujian
 * @Date 2020/8/25 9:46
 */
public class Problem583 {
    /**
     * 两个字符串的删除操作:
     * 给定两个单词word1和word2,找到使得word1和word2相同所需要的最小步数,
     * 每部可以删除任意一个字符串中的一个字符
     * 转换为求两个字符串最大公共子序列的问题
     * @param word1
     * @param word2
     * @return
     */
    public int minDistance(String word1, String word2) {
        int m = word1.length();
        int n = word2.length();
        // dp[i][j]表示word[0....i-1]与word2[0...j-1]的最大公共子序列
        int[][] dp = new int[m+1][n+1];

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



LeetCode139 单词拆分

单词拆分>>>

在这里插入图片描述

  • dp[i]表示前i个元素可以拆分成,则dp[i]= dp[j]&&字典中包含(s.subString(j,i-j))

    // 采用动态规划
    // dp[i] 表示前i个元素能拆分成
    // dp[i] = dp[j]&&wordFictr.contains(s.substr(j,i-j)
    public boolean wordBreak1(String s, List<String> wordDict){
        boolean[] dp = new boolean[s.length()+1];
        dp[0] = true;

        for(int i=1;i<=s.length();i++){
            for(int j=0;j<i;j++){
                // dp[j]表示前j-1个字符可以拆分成
                // j----i
                if(dp[j]&&wordDict.contains(s.substring(j,i))){
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }



LeetCode91 解码方法

LeetCode91 解码方法
在这里插入图片描述

  • dp[i]表示前i个元素有dp[i]个拆分方法,则dp[i] = dp[i-2] +dpi-1

 // 采用动态规划的方法
    public int numDecodings1(String s){
        int[] dp = new int[s.length()+1];
        dp[0] = 1;
        if(s.charAt(0)!=0) {
            dp[1] = 1;
        }else dp[1] = 0;

        for(int i=2;i<dp.length;i++){
            Character cur = s.charAt(i-1);
        // 连续的两个数
            String middlen = s.substring(i-2,i);
            Integer value = Integer.parseInt(middlen);
            //可以连续的取
            if((value>=10&&value<=26)){
                dp[i] = dp[i-2];
            }
            // 可以单独的取一个
            if(cur>0) dp[i]+=dp[i-1];
        }
        return dp[s.length()];
    }

LeetCode44 通配符匹配符

在这里插入图片描述

/**
 * @Author zhoujian
 * @Date 2020/8/20 7:55
 * 通配符匹配
 *      给定一个字符串(s)和一个字符模式(p)
 *      实现一个支持?和*的通配符匹配
 */
public class Problem44 {

    /**
     * 分析:类似最长公共子串,最长公共子序列,编辑距离等求2个字符擦混(或数组)之间的某种关系的题目
     * 一般来说都是用动态规划的解法
     * https://leetcode-cn.com/problems/wildcard-matching/solution/zi-fu-chuan-dong-tai-gui-hua-bi-xu-miao-dong-by-sw/
     * @param s
     * @param p
     * @return
     * dp[i][j] 表示 p 的前 i 个字符和 s 的前 j 个字符是否匹配。
     */
    public boolean isMatch(String s, String p) {
        if(s==null&&p==null) return true;
        if(s==null||p==null) return false;
        int len1 = p.length(), len2 = s.length();
        boolean[][] dp = new boolean[len1 + 1] [len2 + 1];
        dp[0][0] = true;

        // 处理一下匹配串 p 以若干个星号开头的情况。因为星号是可以匹配空串的:
        for (int i = 1; i <= len1; i++) {
            if (p.charAt(i - 1) != '*') {
                break;
            }
            dp[i][0] = true;
        }

        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                // 如果 p[i - 1] == s[j - 1] 或 p[i - 1] == '?',表示当前的字符串是匹配的,dp[i][j] 可以从 dp[i - 1][j - 1] 转移而来。
                if (p.charAt(i - 1) == s.charAt(j - 1) || p.charAt(i - 1) == '?') {
                    dp[i][j] = dp[i - 1][j - 1];
                    //如果 p[i - 1] == '*',这个位置可以匹配 0 到 若干个字符。那么 dp[i][j] 可以从 dp[i - 1][j] 转移而来(表示当前星号没有匹配字符),例如 ab, ab*
                    // 也可以从 dp[i][j - 1] 转移而来(表示当前星号匹配了当前的位置的字符)表示 * 代表的是非空字符,例如 abcd, ab*
                    // 因为只要任意一种匹配即可,所以这里是逻辑或的关系。
                } else if (p.charAt(i - 1) == '*') {
                    dp[i][j] = dp[i - 1][j] | dp[i][j - 1];
                }
            }
        }
        return dp[len1][len2];
    }
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值