题目1:
多多君最近在研究某种数字组合:
定义为:每个数字的十进制表示中(0~9),每个数位各不相同且各个数位之和等于N。
满足条件的数字可能很多,找到其中的最小值即可。
多多君还有很多研究课题,于是多多君找到了你--未来的计算机科学家寻求帮助。
代码:
思路分析:
1、首先最大的数字组合为987654321,和为45,所以大于45的数不存在数字组合。
2、接着如果这个数<10的话,说明最小值肯定是一位数的时候最小,即是它本身。
3、其他情况,因为想要求最小值,所以肯定是希望个位数上的数字尽可能大,高位上的数字尽可能小,才能构成最小值(感觉有点贪心的思想)。
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
if(n > 45){
System.out.println(-1);
return;
}
if(n < 10){
System.out.println(n);
return;
}
int num = 0;
int digit = 0;
for(int i = 9;i > 0;i--){
if(n != 0 && i <= n){
n -= i;
num += (int)Math.pow(10, digit)*i;
digit++;
}
}
System.out.println(num);
}
}
题目2:
多多君最近在研究字符串之间的变换,可以对字符串进行若干次变换操作:
- 交换任意两个相邻的字符,代价为0。
- 将任意一个字符a修改成字符b,代价为 |a - b|(绝对值)。
现在有两个长度相同的字符串X和Y,多多君想知道,如果要将X和Y变成两个一样的字符串,需要的最少的代价之和是多少。
代码:
思路分析:
1、因为交换字符不需要代价,所以选择先将两个字符数组排序
2、然后定义双指针分别指向两个字符数组开始的位置,如果相等则两个指针前进1,否则,需要付出更改元素的代价abs(str1[pre1] - str2[pre2])
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = Integer.parseInt(scan.nextLine());
String s1 = scan.nextLine();
String s2 = scan.nextLine();
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
Arrays.sort(str1);
Arrays.sort(str2);
int pre1 = 0;
int pre2 = 0;
int cost = 0;
for(int i = 0;i < n;i++){
if(str1[i] == str2[i]){
pre1++;
pre2++;
}else{
cost += Math.abs(str1[i] - str2[i]);
}
}
System.out.println(cost);
}
}
题目3:
多多路上从左到右有N棵树(编号1~N),其中第i个颗树有和谐值Ai。
多多鸡认为,如果一段连续的树,它们的和谐值之和可以被M整除,那么这个区间整体看起来就是和谐的。
现在多多鸡想请你帮忙计算一下,满足和谐条件的区间的数量。
代码:
思路分析:
1、数学推理,假设pre[i]代表前i个元素的和,所以[j,i]要满足和谐区间的条件,需要
pre[i] - pre[j-1] = M*(0,1,2,...)
也就是说pre[i] % M取余的值 等于 pre[j-1] % M的值,说明[j,i]区间的和sum是M的倍数。
2、明白以上原理就很好做了,定义一个map来存储前缀和pre出现的次数。但这里要注意的是因为有测试用例数很大,所以不能用int类型,要用Long来定义才能通过测试用例。
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
int[] nums = new int[n];
for(int i = 0;i < n;i++){
nums[i] = scan.nextInt();
}
Map<Long,Long> map = new HashMap<>();
map.put(0L,1L);
long pre = 0;
long count = 0;
for(int i = 0;i < n;i++){
pre += nums[i];
long mod = pre % m;
if(map.containsKey(mod)){
count += map.get(mod);
}
map.put(mod,map.getOrDefault(mod,0L)+1);
}
System.out.println(count);
}
}
题目4:
多多君拼团购买了N个骰子,为了方便后面进行活动,多多君需要将这些骰子进行分类。
两个骰子为同类的定义是:
1
将其中一个骰子通过若干次上下、左右或前后翻转后,其与另一个骰子对应的
6
面数字均相等。
现在多多君想知道不同种类的骰子的数量分别有多少
代码:
思路分析:
找到骰子的规律,就固定1为骰子的上表面,然后看1的四侧对应的值,当1所在位置不同,对应的值不同,可能得出的数不同,所以需要调换顺序之后,存储入map中,key是四个侧面对应的值val,value值是同类型骰子的数量。这题主要还是找规律很难。
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
Map<Integer,Integer> map = new HashMap<>();
for(int n = 1;n <= N;n++){
int[] a = new int[6];
for(int i = 0;i < 6;i++){
a[i] = scan.nextInt();
}
int val = 0;
for(int i = 0;i < 6;i++){
if(a[i] == 1){
if(i % 2 == 0){
val = a[(i+2)%6]*1000 + a[(i+4)%6]*100 + a[(i+3)%6]*10 + a[(i+5)%6];
}else{
val = a[(i+4)%6]*1000 + a[(i+2)%6]*100 + a[(i+3)%6]*10 + a[(i+1)%6];
}
break;
}
}
for(int i = 0,tmp = val;i < 3;i++){
tmp = tmp/10 + (tmp%10*1000);
val = Math.min(val,tmp);
}
map.put(val,map.getOrDefault(val,0)+1);
}
List<Integer> ans = new ArrayList<>();
for(int key : map.keySet()){
ans.add(map.get(key));
}
Collections.sort(ans);
System.out.println(ans.size());
for(int i = ans.size() - 1;i > 0;i--){
System.out.print(ans.get(i) + " ");
}
System.out.println(ans.get(0));
}
}