2022-12-31 leetcode与蓝桥刷题情况

一、leetcode题目

1. 编辑距离

题目描述
给你两个单词 word1word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

2.测试用例

输入:

word1 = “horse”, word2 = “ros”

输出:

3

解释:

horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)

提示

  • 0 <= word1.length, word2.length <= 500
  • word1 和 word2 由小写英文字母组成

3.思路

很明显的动态规划题目,最为稳妥的dp数组定义是dp[i][j]word1的第i个字母结尾和word2的第j个字母结尾的最少操作数。看了一些文字解析,最终分析出了最终结果。下面是dp的一些定义。

  • 状态表示: dp[i][j] 是以word1的第i个字母结尾和word2的第j个字母结尾的最少操作数。
  • 状态转移方程式:
  1. word1[i] == wrod2[j] 时,dp[i][j] = dp[i-1][j-1]
  2. word1[i] != word2[j] 时, dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])(对应为删除一个字符,插入一个字符,以及替换一个字符,在三个中取一个最小值)
  • 边界条件: dp[i][0] = i, dp[0][j] = j;

4.算法实现

class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length(), len2 = word2.length();
        int[][] dp = new int[len1+1][len2+1];
        for(int i = 1; i <= len1; i++) dp[i][0] = i;
        for(int j = 1; j <= len2; j++) dp[0][j] = j;
        for(int i = 1; i <= len1; i++){
            for(int j = 1; j <= len2; j++){
                if(word1.charAt(i-1) == word2.charAt(j-1)) dp[i][j] = dp[i-1][j-1];
                else dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1;
            }
        }
        return dp[len1][len2];
    }
}

二、蓝桥题目

1.最长公共子序列

题目描述
字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列 X = x 0 , x 1 , ⋯   , x m − 1 X={x_0,x_1,\cdots ,x_{m-1}} X=x0,x1,,xm1,序列 Y = y 0 , y 1 , ⋯   , y k − 1 Y={y_0,y_1,\cdots ,y_{k-1}} Y=y0,y1,,yk1 X X X 的子序列,存在 X X X 的一个严格递增下标序列 i 0 , i 1 , ⋯   , i k − 1 {i_0,i_1,\cdots,i_{k-1}} i0,i1,,ik1,使得对所有的 j = 0 , 1 , ⋯   , k − 1. j = 0 , 1 , ⋯ , k − 1 j=0,1,\cdots,k-1.j=0,1,⋯,k−1 j=0,1,,k1.j=0,1,,k1 ,有 x i j = y j x_{ij}=y_j xij=yj 。例如, X X X=ABCBDAB , Y Y Y=BCDB 是 X X X 的一个子序列。对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。
输入描述
第一行为第一个字符序列,都是大写字母组成,以 . 结束。长度小于 5000 5000 5000

第二行为第二个字符序列,都是大写字母组成,以 . 结束,长度小于 5000 5000 5000

输出描述
第一行输出上述两个最长公共子序列的长度。

第二行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对 1 × 1 0 8 1 \times 10^8 1×108求余即可。

2.测试用例

输入:

ABCBDAB.
BACBBD.

输出:

4
7

3.思路

最长公共子序列,老熟人了,动态规划轻松解决,难点是最长公共子序列个数。这部分有借鉴成分,不是完全理解。贴上来自己再多看看。

4.算法实现

import java.util.Scanner;
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        String s1 = scan.next();
        String s2 = scan.next();
        s1 = s1.substring(0, s1.length()-1);
        s2 = s2.substring(0, s2.length()-1);
        int[][] dp = new int[s1.length()+1][s2.length()+1];
        int[][] sum = new int[s1.length()+1][s2.length()+1];
        int mod = (int)1e8;
        for(int i = 0; i < s1.length(); i++) sum[i][0] = 1;
        for(int j = 0; j < s2.length(); j++) sum[0][j] = 1;
        for(int i = 1; i <= s1.length(); i++){
          for(int j = 1; j <= s2.length(); j++){
            if(s1.charAt(i-1) == s2.charAt(j-1)){
              dp[i][j] = dp[i-1][j-1] + 1;
              sum[i][j] = sum[i-1][j-1];
            } 
            else{
              dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
              if(dp[i][j] == dp[i-1][j-1]) sum[i][j] -= sum[i-1][j-1];
            }

            if(dp[i][j] == dp[i-1][j]) sum[i][j] += sum[i-1][j];
            if(dp[i][j] == dp[i][j-1]) sum[i][j] += sum[i][j-1];
            sum[i][j] %= mod;
          }
        }
        System.out.println(dp[s1.length()][s2.length()]);
        System.out.println(sum[s1.length()][s2.length()]);
        scan.close();
    }
}

你可能感兴趣的:(每日算法打卡,leetcode,算法,java,动态规划)