美团-后端笔试真题,2024/03/30

521 阅读9分钟

思路借鉴于 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后乘到答案中。

// 请到公众号或知乎中查看