1.两个字符串的编辑距离
概念
字符串的编辑距离,又称为Levenshtein距离,由俄罗斯的数学家Vladimir Levenshtein在1965年提出。是指利用字符操作,把字符串A转换成字符串B所需要的最少操作数。其中,字符操作包括:
删除一个字符 a) Insert a character
插入一个字符 b) Delete a character
修改一个字符 c) Replace a character
例如对于字符串"if"和"iff",可以通过插入一个'f'或者删除一个'f'来达到目的。
一般来说,两个字符串的编辑距离越小,则它们越相似。如果两个字符串相等,则它们的编辑距离(为了方便,本文后续出现的“距离”,如果没有特别说明,则默认为“编辑距离”)为0(不需要任何操作)。不难分析出,两个字符串的编辑距离肯定不超过它们的最大长度(可以通过先把短串的每一位都修改成长串对应位置的字符,然后插入长串中的剩下字符)。
问题描述
给定两个字符串A和B,求字符串A至少经过多少步字符操作变成字符串B。
学习这个,讲的很细致-->https://blog.csdn.net/ac540101928/article/details/52786435
最后的递推公式:
当 arr1[i-1]==arr2[j-1]
dp[i][j]=dp[i-1][j-1];
否则
dp[i][j]=min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1);
import java.util.*;
public class test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
String A=scanner.nextLine();
String B=scanner.nextLine();
char[] arr1=A.toCharArray();
char[] arr2=B.toCharArray();
int n=A.length();
int m=B.length();
int [][]dp=new int[n+1][m+1];
for(int i=0;i<n+1;i++){
dp[i][0]=i;
}
for(int i=0;i<m+1;i++){
dp[0][i]=i;
}
for(int i=1;i<n+1;i++){
for(int j=1;j<m+1;j++){
if(arr1[i-1]==arr2[j-1]){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]=Math.min(Math.min(dp[i-1][j]+1, dp[i][j-1]+1), dp[i-1][j-1]+1);
}
}
}
// for(int i=0;i<n+1;i++){
// for(int j=0;j<m+1;j++){
// System.out.print(dp[i][j]+" ");
// }
// System.out.println();
// }
System.out.println(dp[n][m]);
}
}
2.给定数组arr,arr中所有的值都是正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求组成aim的最少货币数。(拓展,如果问有多少种不同的找零方法呢)
举例:
arr[5,2,3],aim=20。 4张5元可以组成20元,其他的找钱方案都要使用更多张的货币,所以返回4。
最小纸币个数,自己用的贪心,也不知道对不对
import java.util.*;
public class test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
int []arr={5,2,3};
int aim=scanner.nextInt();
Arrays.sort(arr);
//最小钱的张数
int moneysum=0;
int index=arr.length-1;
//从后向前贪心,后面的货币面额大
while(index>=0){
if(aim/arr[index]!=0){
int temp=aim/arr[index];
moneysum+=temp;
//剩余的钱数
aim-=temp*arr[index];
}
index--;
}
System.out.println(moneysum);
}
}
总共多少种不同的找零方法,一共两种做法
1:一种就是美团2017的那道钱的题(https://blog.csdn.net/wenyimutouren/article/details/80572454)注意初始值的设定;
2:一种就是https://blog.csdn.net/u011468619/article/details/77883263,arr长度为N,生成行数为N,列数为aim+1的矩阵dp。dp[i][j]的含义是在使用arr[0]…arr[i]货币的情况下,组成钱数j的方法数。
- 如果完全不用arr[i]货币,只使用arr[0]…arr[i-1]货币时,方法数为dp[i-1][j]。
- 如果用1张arr[i]货币,剩下的钱使用arr[0.......i-1]货币组成,方法数为dp[i-1][j-1*arr[i]]。
- 如果用2张arr[i]货币,剩下的钱使用arr[0......i-1]货币组成,方法数为dp[i-1][j-2*arr[i]]。
- 如果用3张arr[i]货币,剩下的钱使用arr[0......i-1]货币组成,方法数为dp[i-1][j-3*arr[i]]。
- ……......................
dp[i][j]的值即为上述所有值得累加和。
import java.util.*;
public class test2 {
public static void main(String[] args){
int[] array={2,3,5};
Scanner scanner=new Scanner(System.in);
int aim=scanner.nextInt();
System.out.print(coins2(array,aim));
}
//以前的做法
public static int coins2(int []arr,int aim){
int dp[]=new int [aim+1];
dp[0]=1;
//能被arr[0]整除的设为1(重点)
for(int i=0;i<dp.length;i++){
if(i%arr[0]==0){
dp[i]=1;
}
}
for(int i=1;i<arr.length;i++){
for(int j=arr[i];j<dp.length;j++){
dp[j]=dp[j]+dp[j-arr[i]];
}
}
return dp[aim];
}
//https://blog.csdn.net/u011468619/article/details/77883263
public static int coins(int[] arr,int aim){
int[][] dp=new int[arr.length][aim+1];
for(int i=0;i<arr.length;i++){
dp[i][0]=1;//第一列为1
}
for(int j=1;j<=aim;j++){
if(j%arr[0]==0){
dp[0][j]=1;//第一行中能够被arr[0]整除的数,即可以被换钱,记为1
}else{
dp[0][j]=0;
}
}
for(int i=1;i<arr.length;i++){
for(int j=1;j<=aim;j++){
int temp=0;
for(int k=0;k*arr[i]<=j;k++){
temp+=dp[i-1][j-k*arr[i]];//累加用k张arr[i]货币后dp[i-1]中组成剩下钱数的方法数
}
dp[i][j]=temp;
}
}
return dp[arr.length-1][aim];
}
}