思路借鉴于 2024.3.30美团暑期实习笔试多语言AK指南 和2024.3.30美团暑期实习笔试多语言AK指南,主要是针对真题的二次解释,所有程序仅通过样例,可能存在错误,最后一题暂时没用java重写。
我观察了T3的解法,发现并没有得到官方的输出,所以按照T3给出的输入和输出,重新思考了T3的解法,经测试均通过,当然可能存在错误。
T1
题目描述
众所周知,“全国大学生英语四级考试”(以下简称CET4)的满分为 710 分。在经过三次的 CET4 考试后,小美终于如愿通过了四级。已知 CET4 的总分数由三大项构成,分别是:听力,阅读,写作。现在已知小美的总分,且他的“写作”得分比"听力"高了分,比"阅读”得分低了分,你能求出他的三个大项分别得了多少分吗?
输入描述
输入包含一行三个整数,分别表示题中所述的,(保证输入合法,即保证算出的答案一定是正整数)
输出描述
输出包含三个非负整数。,分别表示小美"听力","阅读”,"写作”二大项分别的得分
样例
输入
441 1 -20
输出
153 134 154
思路:模拟 先求出听力,再求其它。
import java.util.Scanner;
public class Lian1 {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int k = sc.nextInt();
int x = sc.nextInt();
int y = sc.nextInt();
int c = (k + x - y)/3; // 先求出听力
System.out.println((c - x) + " " + (c + y) + " " + c); // 再输出其它
}
}
T2
题目描述
小美拿到了一个数组。她定义为:将第个元素翻倍后,数组的最大值。现在小美希望你求出到的值。你能帮帮她吗?
输入描述
第一行输入一个正整数n,代表数组大小
第二行输入n个正整数ai,代表小红拿到的数组
输出描述
n个正整数,用空格隔开,代表f[0]到f[1]的值
样例
输入
5
1 3 2 5 4
输出
5 6 5 10 8
思路:模拟
先遍历整个数组a[],得到最大值max,再遍历整个数组a[],每个元素a[i]与max比较,取最大值作f[i]再输出
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int max = Integer.MIN_VALUE;
int n = sc.nextInt();
int[] a = new int[n];
for(int i = 0; i < n; i++){
a[i] = sc.nextInt();
max = a[i] > max ? a[i] : max; // 得到最大值max
}
for(int i = 0; i < n; i++){
a[i] = 2 * a[i] > max ? 2 * a[i] : max; // 取a[i]与max的最大值
System.out.print(a[i] + " "); // 输出
}
}
}
T3
题目描述
小美有两个长度相等的字符串,第一个字符串为 s ,第二个字符串为 t 。
小美每次可以选择一个字符串的一个前缀,然后选择一个字母 c ,将选择的前缀的所有字母都变成 c 。
小美想知道她最少要操作几次可以使得 s 和 t 相等。
输入描述
第一行输入一个长度不超过 的字符串 。
第二行输入一个长度与 相等的字符串 。
输出描述
第一行输出一个整数表示答案。
接下来 m 行,每行输出用空格隔开的 表示选择第 个字符串的长度为 的前缀,将前缀所有字母变成 c 。
样例
输入
aabc
abcc
输出
2
2 3 b
2 2 a
说明
第1次操作选择第2个字符串的长度为3的前缀,将前缀所有字母变成 'b' ,字符串变成 "bbbc" 。
第2次操作选择第2个字符串的长度为2的前缀,将前缀所有字母变成 'a' ,字符串变成 "aabc" 。
构造的输入和输出
输入
aabbb
abccd
输出
2
1 5 a
2 5 a
输入
aacbd
bbbbd
输出
1
1 3 b
输入
aacbd
bbbcd
输出
2
1 4 c
1 3 b
输入
bbbcd
aacbd
输出
2
2 4 c
2 3 b
思路:思维题 分类讨论
能够实现官方给出的输入/输出,但是对于s = aabb,t = acdb 此类的输出,不能如 2 4 b,2 2 a这样输出,只能按 1 4 a(任意字符), 2 4 a(任意字符)。
import java.util.Scanner;
// 假设s、t这两个字符串各有两个前指针f1、f2,后指针end.
public class T3 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
String t = scanner.next();
int n = s.length();
int end = s.length() - 1; // 后指针end
while (end >= 0 && s.charAt(end) == t.charAt(end)) { // 从最后一位向前,判断s[end],t[end]是否相等
end--;
}
int f1 = 0, f2 = 0;
while (f1 < end && s.charAt(f1) == s.charAt(f1+1)) { // 判断s字符串前缀字符是否一致
f1++; // 如果一致,指针往后移一位
}
while (f2 < end && t.charAt(f2) == t.charAt(f2+1)) { // 判断s字符串前缀字符是否一致
f2++; // 如果一致,指针往后移一位
}
if(end < 0){
System.out.println(0);
} else if (end == f1) { // s字符串后指针与前指针相遇,说明只需要将t字符串前end+1个字符置为s.charAt(end)。
System.out.println(1);
System.out.println("2 " + (end+1) + " " + s.charAt(end));
} else if (end == f2){ // t字符串后指针与前指针相遇,说明只需要将s字符串前end+1个字符置为t.charAt(end)。
System.out.println(1);
System.out.println("1 " + (end+1) + " " + t.charAt(end));
}
else if (end - f1 == 1) { // 不连续,但只有一个字符不同,如 s = aabd t = cacd
System.out.println(2);
System.out.println("2 " + (end+1) + " " + s.charAt(end));
System.out.println("2 " + (f1+1) + " " + s.charAt(f1));
}else if (end - f2 == 1) { // 不连续,但只有一个字符不同,如 s = cacd t = aabd
System.out.println(2);
System.out.println("1 " + (end+1) + " " + t.charAt(end));
System.out.println("1 " + (f2+1) + " " + t.charAt(f2));
}else { // 无法处理,只能最后一位到第一位,同时置为"a"(也可以是其它字符)
System.out.println(2);
System.out.println("1 " + n + " a");
System.out.println("2 " + n + " a");
}
}
}
T4
题目描述
小美定义一个字符串是平衡串,当且仅当该字符串仅包含两种字符,且两种字符出现的次数相等。例如"ababba"是平衡串。现在小美拿到了一个仅由小写字母组成的字符串,她想知道该字符串有多少子序列是平衡串?定义子序列为从左到右取若干个字符(可以不连续)组成的字符串。例如,"aca"是"arcaea"的子序列。
输入描述
第一行输入一个正整数,代表字符串长度。第二行输入一个长度为的、仅由小写字母组成的字符串。
输出描述
输出一个整数表示答案,由于答案可能很大,请输出答案对 取模的结果。
样例
输入
5
ababc
输出
9
说明
长度为 2 的子序列,共有 8 个。
长度为 4 的子序列,共有 1 个。
思路:组合计数 乘法逆元
本题叕是一道组合计数+乘法逆元的数论题,本题是子序列,因此可以对每个字符出现的次数进行统计,总共只有26种字符
考虑任意两个字符和,分别出现了次和次,那么我们可以分别枚举其出现次数相同的子序列的长度分别有
对于字符和均出现次,对于字符来说,我们根据组合计数可以得知有中选择,对于字符有种选择
但是如果直接这样暴力枚举,可能会超时
因此有一种优化的方式
我们首先考虑所有出现次数为的字符对应的的总和,记为
- 对于字符 a 出现的合法子序列有
- 对于字符 b 出现的合法子序列有
上述把所有的情况重复考虑了一次,因此还需要把对应结果除以2(乘以2的逆元)
由于本题数据范围较大,因此需要使用乘法逆元来计算组合数,跟上午蚂蚁的笔试模版基本上一模一样,大家可以学习一下,笔试题单也有对应的模板~
T5
题目描述
小美有个朋友,她准备请其中一些朋友来吃饭。其中有一些朋友有暗恋关系:假设a暗恋b,那么小美带上b的时候a也必须去,否则a就会不开心。小美想知道,一共有多少种不同的请客方案可以让每个人都开心?由于答案可能过大,请对取模。
输入描述
第一行输入两个正整数,代表小美的朋友数量、暗恋的关系数量。接下来的m行,每行输入两个正整数,代表第个人暗恋第个人。保证每个人最多只会暗恋一个人。
输出描述
一个整数,代表小美的请客方案数。
样例1
输入
2 1
1 2
输出
2
说明
两个方案:只请 1 号,或者同时请 1 号和 2 号。
请注意,不能只请 2 号,否则 1 号会不开心。
样例2
输入
3 3
1 2
2 3
3 1
输出
1
说明
显然 3 个人必须全部请客,否则总有人会不开心。
思路:图论 Tarjan算法 本题如果是暗恋,他们两个聚餐时任意一个去了对方都要去的话,是满足并查集的条件的(也就是无向图),但是本题显然是单相思问题有向图问题,因此就不能用无向图的方式来处理(如果是无向图,直接并查集或者DFS扫一遍连通块个数就可以做)
对于有向图问题,我们可以考虑使用图论中的Tarjan算法,来计算图的强连通分量,然后对于将这个图拆分的若干个强连通分量进行处理。
Tarjan算法是一种基于深度优先搜索的算法,可以在的时间复杂度内找出有向图的所有强连通分量。强连通分量是有向图中的一个子图,任意两个节点都是互相可达的。
在找出所有的强连通分量后,我们可以将原图转化为一个新的图,其中每个节点代表一个强连通分量。如果两个强连通分量之间有边,则在新图中也有对应的边。这样,原图就被转化为了一个DAG(有向无环图)。
对于这个DAG,我们可以进行深度优先搜索,计算每个节点的值。值表示从当前节点出发可以到达的路径数量。对于每个入度为0的节点(即没有其他节点指向它的节点),将其值加1后乘到答案中。
// 请到公众号或知乎中查看