2022-5-22 笔试真题练习
多多的数字组合
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M
多多君最近在研究某种数字组合:
定义为:每个数字的十进制表示中(0~9),每个数位各不相同且各个数位之和等于N。
满足条件的数字可能很多,找到其中的最小值即可。
定义为:每个数字的十进制表示中(0~9),每个数位各不相同且各个数位之和等于N。
满足条件的数字可能很多,找到其中的最小值即可。
多多君还有很多研究课题,于是多多君找到了你--未来的计算机科学家寻求帮助。
数据范围:
进阶:空间复杂度 ,时间复杂度
进阶:空间复杂度 ,时间复杂度
输入描述:
共一行,一个正整数N,如题意所示,表示组合中数字不同数位之和。
(1 <= N <= 1,000)
输出描述:
共一行,一个整数,表示该组合中的最小值。
如果组合中没有任何符合条件的数字,那么输出-1即可。
1 import java.util.*; 2 public class Main{ 3 static int ans; 4 static boolean f; 5 public static void main(String[] args){ 6 Scanner sc=new Scanner(System.in); 7 int n=sc.nextInt(); 8 List<Integer> res=new ArrayList<>(); 9 Set<Integer> set=new HashSet<>(); 10 f=false; 11 ans=Integer.MAX_VALUE; 12 dfs(0,n,res,set); 13 // 找到一组互不相同的数字 使得和为n 14 // 0不会使得变化 加进去 肯定放在最前面 直接不考虑0 15 if (f){ 16 System.out.print(ans); 17 }else{ 18 System.out.print(-1); 19 } 20 } 21 22 public static void dfs(int sum,int target,List<Integer> res,Set<Integer> set){ 23 if (sum>target) return; 24 if (sum==target){ 25 StringBuffer sb=new StringBuffer(); 26 for (int i:res){ 27 sb.append(i); 28 } 29 ans=Math.min(ans,Integer.parseInt(sb.toString())); 30 f=true; 31 return; 32 } 33 for (int i=1;i<=9;i++){ 34 if (!set.contains(i)){ 35 set.add(i); 36 res.add(i); 37 dfs(sum+i,target,res,set); 38 set.remove(i); 39 res.remove(res.size()-1); 40 } 41 } 42 } 43 }
思路:dfs深度搜索所有可能性。如果穷举需要1~9876543210,会超时。
多多的字符变换
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M
多多君最近在研究字符串之间的变换,可以对字符串进行若干次变换操作:
- 交换任意两个相邻的字符,代价为0。
- 将任意一个字符a修改成字符b,代价为 |a - b|(绝对值)。
现在有两个长度相同的字符串X和Y,多多君想知道,如果要将X和Y变成两个一样的字符串,需要的最少的代价之和是多少。
输入描述:
共三行,第一行,一个整数N,表示字符串的长度。
(1 <= N <= 2,000)
接下来两行,每行分别是一个字符串,表示字符串X和Y。
(字符串中仅包含小写字母)
输出描述:
共一行,一个整数,表示将X和Y变换成一样的字符串需要的最小的总代价。
1 import java.util.*; 2 public class Main{ 3 public static void main(String[] args){ 4 Scanner sc=new Scanner(System.in); 5 int n=sc.nextInt(); 6 sc.nextLine(); 7 String a=sc.nextLine(); 8 String b=sc.nextLine(); 9 int[] cnt1=new int[26]; 10 int[] cnt2=new int[26]; 11 for (int i=0;i<n;i++){ 12 char c1=a.charAt(i); 13 char c2=b.charAt(i); 14 cnt1[c1-'a']++; 15 cnt2[c2-'a']++; 16 } 17 for (int i=0;i<26;i++){ 18 int t=Math.min(cnt1[i],cnt2[i]); 19 cnt1[i]-=t; 20 cnt2[i]-=t; 21 } 22 int sum=0; 23 int p=0; 24 for (int i=0;i<26;i++){ 25 while (cnt2[i]!=0){ 26 while (cnt1[p]==0) p++; 27 int t=Math.min(cnt1[p],cnt2[i]); 28 sum+=t*Math.abs(p-i); 29 cnt1[p]-=t; 30 cnt2[i]-=t; 31 // 如果cnt2==0 直接结束 32 // 33 } 34 } 35 System.out.print(sum); 36 } 37 }
思路:交换字符的代价为0,所以相同的字符总是可以通过交换使得代价为0。剩下的字符从匹配串开始升序遍历,最优的总是优先匹配前面的代价最小(贪心)
比如 a c 需要匹配d 虽然c到d代价较小,但是d后面的字符匹配a会更大。