题目描述
给你两个单词 word1
和 word2
, 请返回将 word1
转换成 word2
所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
输入:
word1 = “horse”, word2 = “ros”
输出:
3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
提示
很明显的动态规划题目,最为稳妥的dp数组定义是dp[i][j]
以word1
的第i
个字母结尾和word2
的第j
个字母结尾的最少操作数。看了一些文字解析,最终分析出了最终结果。下面是dp的一些定义。
word1
的第i
个字母结尾和word2
的第j
个字母结尾的最少操作数。word1[i] == wrod2[j]
时,dp[i][j] = dp[i-1][j-1]
word1[i] != word2[j]
时, dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
(对应为删除一个字符,插入一个字符,以及替换一个字符,在三个中取一个最小值)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];
}
}
题目描述
字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列 X = x 0 , x 1 , ⋯ , x m − 1 X={x_0,x_1,\cdots ,x_{m-1}} X=x0,x1,⋯,xm−1,序列 Y = y 0 , y 1 , ⋯ , y k − 1 Y={y_0,y_1,\cdots ,y_{k-1}} Y=y0,y1,⋯,yk−1 是 X X X 的子序列,存在 X X X 的一个严格递增下标序列 i 0 , i 1 , ⋯ , i k − 1 {i_0,i_1,\cdots,i_{k-1}} i0,i1,⋯,ik−1,使得对所有的 j = 0 , 1 , ⋯ , k − 1. j = 0 , 1 , ⋯ , k − 1 j=0,1,\cdots,k-1.j=0,1,⋯,k−1 j=0,1,⋯,k−1.j=0,1,⋯,k−1 ,有 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求余即可。
输入:
ABCBDAB.
BACBBD.
输出:
4
7
最长公共子序列,老熟人了,动态规划轻松解决,难点是最长公共子序列个数。这部分有借鉴成分,不是完全理解。贴上来自己再多看看。
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();
}
}