【链家】2018宣讲笔试

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.给定数组arrarr中所有的值都是正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数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的方法数。

  1. 如果完全不用arr[i]货币,只使用arr[0]…arr[i-1]货币时,方法数为dp[i-1][j]。
  2. 如果用1张arr[i]货币,剩下的钱使用arr[0.......i-1]货币组成,方法数为dp[i-1][j-1*arr[i]]。
  3. 如果用2张arr[i]货币,剩下的钱使用arr[0......i-1]货币组成,方法数为dp[i-1][j-2*arr[i]]。
  4. 如果用3张arr[i]货币,剩下的钱使用arr[0......i-1]货币组成,方法数为dp[i-1][j-3*arr[i]]。
  5. ……......................

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];
	}
	
}

猜你喜欢

转载自blog.csdn.net/wenyimutouren/article/details/81806553