【备战春招必看】美团2025届春招第3套笔试解析 | 大厂真题通关指南

✅ 春招备战指南 ✅

💡 学习建议:

  • 先尝试独立解题(建议用时:90分钟/套)
  • 对照解析查漏补缺
  • 配套练习题库

互联网必备刷题宝典🔗

📢 美团技术岗笔试重要信息速览

⏰ 笔试时间安排

  • 常规场次:每周六交替进行
    • 上午场 10:00~11:30
    • 晚间场 19:00~20:30
  • 通知时间:每周四/五通过邮箱发送考试链接

🧩 笔试题型分布

岗位类型题目构成
算法岗选择题 + 5道编程
后端开发岗选择题 + 3道编程
前端/测试岗选择题 + 2道编程

⚙️ 考试设置要点

  • 考试平台:牛客网(ACM模式)
  • 监考要求
    • 必须开启笔记本前置摄像头
    • 禁止使用手机(需小程序锁定)
    • 允许使用本地IDE
  • 编程规范
    • 严格遵循输入输出格式
    • 注意时间复杂度控制(通常1s对应1e8次运算)

📚 笔试经验贴

(所有展示题面均已进行改编处理,保留核心考点)

本题库收录整理自:

  1. 互联网公开的笔试真题回忆版(经网友投稿)
  2. 各大技术社区公开讨论的经典题型
  3. 历年校招考生提供的解题思路

🔍 题库特点:

  • 100%真实笔试场景还原
  • 包含高频考点题型
  • 提供多语言实现参考
  • 持续更新2024届最新真题

⚠️ 注意事项:

  1. 所有题目均来自公开渠道,已进行改编脱敏处理
  2. 实际笔试可能出现题型变化,请以官方通知为准

🚀 春招备战指南

金三银四求职季即将到来!这里整理了最新美团真题及解析,助你快速掌握笔试套路。建议重点突破以下题型:

  1. 数组/字符串操作
  2. 树形结构应用
  3. 贪心/动态规划
  4. 区间合并问题

(👇 下附最新笔试真题及详细解析 👇)


真题详解(改编版)

T1 矩阵子矩形

题目描述

小基拿到了一个 n n n m m m列的矩阵,他想知道该矩阵有多少个 2 ∗ 2 2*2 22的子矩形满足1和0数量相等。

输入描述

第一行为 n n n m m m

接下来 n n n行,每行为长度为 m m m的01串,用来表示矩阵。

2 ≤ n , m ≤ 100 2\le n,m\le 100 2n,m100

输出描述

一个整数,表示答案。

样例1

输入:

2 3
110
010

输出:

1

题解

这是一道简单的模拟题,主要考察基本的数学运算。

解题思路如下:

  1. 遍历矩阵,对每个 2 ∗ 2 2*2 22的矩阵统计0和1的个数。
  2. 如果相等,则答案加一。
  3. 可以直接将四个格子的值加起来,如果相等,那么和为2。

时间复杂度: O ( n m ) O(nm) O(nm),其中 n n n m m m是矩阵的行数和列数。

参考代码

C++:

#include <bits/stdc++.h>
using namespace std;
#define ll long long

int n,m,cnt,ans=0;
char a[105][105];

int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%s",a[i]+1);
    }
    for(int i=1;i<n;++i){
        for(int j=1;j<m;++j){
            cnt = a[i][j]-'0' + a[i+1][j]-'0' + a[i][j+1]-'0' + a[i+1][j+1]-'0';
            if(cnt==2){
                ans++;
            }
        }
    }
    printf("%d",ans);
    return 0;
}

Python:

n = int(input())
matrix = []
for _ in range(n):
    matrix.append(input())

prefixSum = [[0] * (m + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
    for j in range(1, m + 1):
        prefixSum[i][j] = (1 if matrix[i-1][j-1] == '1' else 0) + prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1]

res = 0
for i in range(2, n+1):
    for j in range(2, m+1):
        if prefixSum[i][j] - prefixSum[i-2][j] - prefixSum[i][j-2] + prefixSum[i-2][j-2] == 2:
            res += 1
print(res)

Java:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        char[][] a = new char[n+1][m+1];
        for(int i = 1; i <= n; i++) {
            String s = sc.next();
            for(int j = 1; j <= m; j++) {
                a[i][j] = s.charAt(j-1);
            }
        }
        int ans = 0;
        for(int i = 1; i < n; i++) {
            for(int j = 1; j < m; j++) {
                int cnt = (a[i][j]-'0') + (a[i+1][j]-'0') + (a[i][j+1]-'0') + (a[i+1][j+1]-'0');
                if(cnt == 2) ans++;
            }
        }
        System.out.println(ans);
    }
}

T2 字符串规范化

题目描述

小基定义以下三种单词是合法的:

  1. 所有字母都是小写。例如:good。
  2. 所有字母都是大写。例如:APP。
  3. 第一个字母大写,后面所有字母都是小写。例如:Alice。

现在小基拿到了一个单词,他每次操作可以修改任意一个字符的大小写。小基想知道最少操作几次可以使得单词变成合法的?

输入描述

一个仅由大写字母和小写字母组成的字符串,长度不超过 1 0 5 10^5 105

输出描述

一个整数,代表操作的最小次数。

样例1

输入:

AbC

输出:

1

说明:变成ABC或者Abc均可。只需要1次操作。

题解

这道题需要考虑三种合法情况,分别计算达到每种情况需要的最小操作次数。

解题思路:

  1. 统计字符串中大写字母和小写字母的数量。
  2. 考虑三种合法情况:
    • 全部变成小写:需要修改的次数是大写字母的数量
    • 全部变成大写:需要修改的次数是小写字母的数量
    • 首字母大写其余小写:需要考虑首字母是否需要修改,以及其余字母变成小写需要的修改次数
  3. 取三种情况中的最小值。

时间复杂度: O ( n ) O(n) O(n),其中 n n n是字符串长度。

参考代码

C++:

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string s;
    cin >> s;
    int upper = 0, lower = 0;
    for(char c : s) {
        if(isupper(c)) upper++;
        else lower++;
    }
    int n = s.size();
    int ans = min(upper, lower); // 全部变成一种情况
    
    // 首字母大写,其余小写
    int firstCase = (islower(s[0]) ? 1 : 0) + upper - (isupper(s[0]) ? 1 : 0);
    ans = min(ans, firstCase);
    
    cout << ans << endl;
    return 0;
}

Python:

s = input()
upper = sum(1 for c in s if c.isupper())
lower = len(s) - upper

ans = min(upper, lower)  # 全部变成一种情况
# 首字母大写,其余小写
first_case = (s[0].islower()) + upper - (s[0].isupper())
ans = min(ans, first_case)

print(ans)

Java:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int upper = 0, lower = 0;
        
        for(char c : s.toCharArray()) {
            if(Character.isUpperCase(c)) upper++;
            else lower++;
        }
        
        int n = s.length();
        int ans = Math.min(upper, lower);
        
        // 首字母大写,其余小写
        int firstCase = (Character.isLowerCase(s.charAt(0)) ? 1 : 0) + 
                       upper - (Character.isUpperCase(s.charAt(0)) ? 1 : 0);
        ans = Math.min(ans, firstCase);
        
        System.out.println(ans);
    }
}

T3 数组翻倍

题目描述

小基拿到了一个排列,所有元素为红色或者白色。

小基可以交换任意两个红色元素的位置,并希望用最少次数使得数组变为非降序。最少要用多少次?

输入描述

第一行一个正整数 n ( n ≤ 1 0 5 ) n(n\le10^5) n(n105),表示数组的长度。

第二行 n n n个正整数 a i a_i ai

第三行为一个长为 n n n的字符串,表示染色情况, R R R为红色, W W W为白色。

输出描述

一个整数,表示答案。如果无法完成,则输出-1。

样例1

输入:

4
1 3 2 4
WRRW

输出:

1

题解

这道题可以使用哈希表和模拟来解决。

解题思路:

  1. 对于每个位置,初始翻倍次数为操作总次数 q q q
  2. 当某个位置被指定为不翻倍时,该位置的翻倍次数减1。
  3. 使用快速幂计算每个位置最终的值: a i × 2 c n t i a_i \times 2^{cnt_i} ai×2cnti
  4. 所有位置的值求和并取模。

时间复杂度: O ( n log ⁡ q ) O(n \log q) O(nlogq),其中快速幂的复杂度是 O ( log ⁡ q ) O(\log q) O(logq)

参考代码

C++:

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;

long long quick_pow(long long a, long long b) {
    long long res = 1;
    while(b) {
        if(b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for(int i = 0; i < n; i++) cin >> a[i];
    
    vector<int> cnt(n, q);
    for(int i = 0; i < q; i++) {
        int x;
        cin >> x;
        cnt[x-1]--;
    }
    
    long long ans = 0;
    for(int i = 0; i < n; i++) {
        ans = (ans + a[i] * quick_pow(2, cnt[i])) % MOD;
    }
    cout << ans << endl;
    return 0;
}

Python:

MOD = 10**9 + 7
n = int(input())
a = list(map(int, input().split()))
cnt = [q] * n

for _ in range(q):
    x = int(input())
    cnt[x-1] -= 1

ans = 0
for i in range(n):
    ans = (ans + a[i] * pow(2, cnt[i], MOD)) % MOD
print(ans)

Java:

import java.util.*;

public class Main {
    static final int MOD = 1000000007;
    
    static long quickPow(long a, long b) {
        long res = 1;
        while(b > 0) {
            if((b & 1) == 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        int[] a = new int[n];
        for(int i = 0; i < n; i++) a[i] = sc.nextInt();
        
        int[] cnt = new int[n];
        Arrays.fill(cnt, q);
        
        for(int i = 0; i < q; i++) {
            int x = sc.nextInt();
            cnt[x-1]--;
        }
        
        long ans = 0;
        for(int i = 0; i < n; i++) {
            ans = (ans + a[i] * quickPow(2, cnt[i])) % MOD;
        }
        System.out.println(ans);
    }
}

T4 区间众数

题目描述

小基拿到了一个数组,他希望你求出所有区间众数之和。定义区间的众数为出现次数最多的那个数,如果有多个数出现次数最多,那么众数是其中最小的那个数。

输入描述

第一行输入一个正整数 n n n,代表数组的大小。

第二行输入 n n n个正整数 a i a_i ai,代表数组的元素。

数据范围:

  • 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105
  • 1 ≤ a i ≤ 2 1 \leq a_i \leq 2 1ai2

输出描述

一个正整数,代表所有区间的众数之和。

样例1

输入:

3
2 1 2

输出:

9

说明:

  • [2],[2,1,2],[2] 的众数是 2
  • [2,1],[1],[1,2] 的众数是 1
    因此答案是 9。

题解

这道题可以使用前缀和和树状数组来解决。

解题思路:

  1. 由于数组元素只有1和2,可以将1视为-1,2视为1。
  2. 计算前缀和,区间和大于0表示2的数量多,否则1的数量多或相等。
  3. 使用树状数组维护区间统计。

时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn)

参考代码

C++:

#include <bits/stdc++.h>
using namespace std;

int lowbit(int x) { return x & (-x); }

void update(vector<int>& tree, int pos, int val) {
    while(pos < tree.size()) {
        tree[pos] += val;
        pos += lowbit(pos);
    }
}

int query(vector<int>& tree, int pos) {
    int sum = 0;
    while(pos > 0) {
        sum += tree[pos];
        pos -= lowbit(pos);
    }
    return sum;
}

int main() {
    int n;
    cin >> n;
    vector<int> a(n+1);
    vector<int> tree(n+1);
    
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
        a[i] = (a[i] == 2 ? 1 : -1);
    }
    
    long long ans = 0;
    int sum = 0;
    update(tree, n/2, 1);  // 初始化
    
    for(int i = 1; i <= n; i++) {
        sum += a[i];
        ans += query(tree, sum + n/2);
        update(tree, sum + n/2 + 1, 1);
    }
    
    cout << ans << endl;
    return 0;
}

Python:

def lowbit(x):
    return x & (-x)

def update(tree, pos, val):
    while pos < len(tree):
        tree[pos] += val
        pos += lowbit(pos)

def query(tree, pos):
    sum = 0
    while pos > 0:
        sum += tree[pos]
        pos -= lowbit(pos)
    return sum

n = int(input())
a = [0] + list(map(lambda x: 1 if x == 2 else -1, map(int, input().split())))
tree = [0] * (n+1)

ans = 0
sum = 0
update(tree, n//2, 1)

for i in range(1, n+1):
    sum += a[i]
    ans += query(tree, sum + n//2)
    update(tree, sum + n//2 + 1, 1)

print(ans)

Java:

import java.util.*;

public class Main {
    static int lowbit(int x) {
        return x & (-x);
    }
    
    static void update(int[] tree, int pos, int val) {
        while(pos < tree.length) {
            tree[pos] += val;
            pos += lowbit(pos);
        }
    }
    
    static int query(int[] tree, int pos) {
        int sum = 0;
        while(pos > 0) {
            sum += tree[pos];
            pos -= lowbit(pos);
        }
        return sum;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n+1];
        int[] tree = new int[n+1];
        
        for(int i = 1; i <= n; i++) {
            a[i] = sc.nextInt();
            a[i] = (a[i] == 2 ? 1 : -1);
        }
        
        long ans = 0;
        int sum = 0;
        update(tree, n/2, 1);
        
        for(int i = 1; i <= n; i++) {
            sum += a[i];
            ans += query(tree, sum + n/2);
            update(tree, sum + n/2 + 1, 1);
        }
        
        System.out.println(ans);
    }
}

T5 排列取反

题目描述

小基拿到了一个排列,他定义 f ( i ) f(i) f(i)为:将第 i i i个元素取反后,形成的数组的逆序对数量。小基希望你求出 f ( 1 ) f(1) f(1) f ( n ) f(n) f(n)的值。排列是指一个长度为 n n n的数组,1到 n n n每个元素恰好出现了一次。

输入描述

第一行输入一个正整数 n n n,代表排列的大小。

第二行输入 n n n个正整数 a i a_i ai,代表排列的元素。

数据范围:

  • 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105
  • 1 ≤ a i ≤ n 1 \leq a_i \leq n 1ain

输出描述

输出 n n n个整数,第 i i i个整数是 f ( i ) f(i) f(i)的值。

样例1

输入:

3
1 2 3

输出:

0 1 2

说明:

  • 第一个元素取反,数组变成 [-1,2,3],逆序对数量为 0
  • 第二个元素取反,数组变成 [1,-2,3],逆序对数量为 1
  • 第三个元素取反,数组变成 [1,2,-3],逆序对数量为 2

题解

这道题可以使用树状数组来维护逆序对的数量。

解题思路:

  1. 首先计算原数组的逆序对数量。
  2. 对于每个位置i:
    • 将该位置的数取反后,会与左边所有数形成新的逆序对
    • 同时会与右边的某些数消除原有的逆序对
  3. 使用树状数组维护区间统计。

时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn)

参考代码

Python:

def lowbit(x):
    return x & -x

def query(tree, pos):
    res = 0
    while pos > 0:
        res += tree[pos]
        pos -= lowbit(pos)
    return res

def update(tree, pos, val):
    while pos < len(tree):
        tree[pos] += val
        pos += lowbit(pos)

n = int(input())
a = [0] + list(map(int, input().split()))
b = [0] * (n+1)
tr1 = [0] * (n+1)
tr2 = [0] * (n+1)

# 计算原始逆序对
ans = 0
for i in range(1, n+1):
    val = query(tr1, n) - query(tr1, a[i])
    ans += val
    b[i] += val
    update(tr1, a[i], 1)

# 计算取反后的影响
for i in range(n, 0, -1):
    b[i] += query(tr2, a[i])
    update(tr2, a[i], 1)

# 输出结果
for i in range(1, n+1):
    print(ans - b[i] + i - 1, end=" ")

C++:

#include <bits/stdc++.h>
using namespace std;

int lowbit(int x) { return x & (-x); }

void update(vector<int>& tree, int pos, int val) {
    while(pos < tree.size()) {
        tree[pos] += val;
        pos += lowbit(pos);
    }
}

int query(vector<int>& tree, int pos) {
    int sum = 0;
    while(pos > 0) {
        sum += tree[pos];
        pos -= lowbit(pos);
    }
    return sum;
}

int main() {
    int n;
    cin >> n;
    vector<int> a(n+1), b(n+1);
    vector<int> tr1(n+1), tr2(n+1);
    
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    long long ans = 0;
    for(int i = 1; i <= n; i++) {
        int val = query(tr1, n) - query(tr1, a[i]);
        ans += val;
        b[i] += val;
        update(tr1, a[i], 1);
    }
    
    for(int i = n; i > 0; i--) {
        b[i] += query(tr2, a[i]);
        update(tr2, a[i], 1);
    }
    
    for(int i = 1; i <= n; i++) {
        cout << ans - b[i] + i - 1 << " ";
    }
    cout << endl;
    return 0;
}

Java:

import java.util.*;

public class Main {
    static int lowbit(int x) {
        return x & (-x);
    }
    
    static void update(int[] tree, int pos, int val) {
        while(pos < tree.length) {
            tree[pos] += val;
            pos += lowbit(pos);
        }
    }
    
    static int query(int[] tree, int pos) {
        int sum = 0;
        while(pos > 0) {
            sum += tree[pos];
            pos -= lowbit(pos);
        }
        return sum;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n+1];
        int[] b = new int[n+1];
        int[] tr1 = new int[n+1];
        int[] tr2 = new int[n+1];
        
        for(int i = 1; i <= n; i++) a[i] = sc.nextInt();
        
        long ans = 0;
        for(int i = 1; i <= n; i++) {
            int val = query(tr1, n) - query(tr1, a[i]);
            ans += val;
            b[i] += val;
            update(tr1, a[i], 1);
        }
        
        for(int i = n; i > 0; i--) {
            b[i] += query(tr2, a[i]);
            update(tr2, a[i], 1);
        }
        
        for(int i = 1; i <= n; i++) {
            System.out.print((ans - b[i] + i - 1) + " ");
        }
        System.out.println();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值