✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题(建议用时:90分钟/套)
- 对照解析查漏补缺
- 配套练习题库
互联网必备刷题宝典🔗
📢 美团技术岗笔试重要信息速览
⏰ 笔试时间安排
- 常规场次:每周六交替进行
- 上午场 10:00~11:30
- 晚间场 19:00~20:30
- 通知时间:每周四/五通过邮箱发送考试链接
🧩 笔试题型分布
| 岗位类型 | 题目构成 |
|---|---|
| 算法岗 | 选择题 + 5道编程 |
| 后端开发岗 | 选择题 + 3道编程 |
| 前端/测试岗 | 选择题 + 2道编程 |
⚙️ 考试设置要点
- 考试平台:牛客网(ACM模式)
- 监考要求:
- 必须开启笔记本前置摄像头
- 禁止使用手机(需小程序锁定)
- 允许使用本地IDE
- 编程规范:
- 严格遵循输入输出格式
- 注意时间复杂度控制(通常1s对应1e8次运算)
📚 笔试经验贴
(所有展示题面均已进行改编处理,保留核心考点)
本题库收录整理自:
- 互联网公开的笔试真题回忆版(经网友投稿)
- 各大技术社区公开讨论的经典题型
- 历年校招考生提供的解题思路
🔍 题库特点:
- 100%真实笔试场景还原
- 包含高频考点题型
- 提供多语言实现参考
- 持续更新2024届最新真题
⚠️ 注意事项:
- 所有题目均来自公开渠道,已进行改编脱敏处理
- 实际笔试可能出现题型变化,请以官方通知为准
🚀 春招备战指南
金三银四求职季即将到来!这里整理了最新美团真题及解析,助你快速掌握笔试套路。建议重点突破以下题型:
- 数组/字符串操作
- 树形结构应用
- 贪心/动态规划
- 区间合并问题
(👇 下附最新笔试真题及详细解析 👇)
真题详解(改编版)
题目 1: 桶装水问题
题目描述
小基有 3 3 3 个桶,容量分别为 a , b , c a,b,c a,b,c 单位。他想要把 n n n 单位的水用这三个桶装走。每一趟他都可以选择更换一个桶或继续使用当前的桶,装满水后拎到终点将水倒掉,再回来继续装下一趟。小基想要快快完成任务,他想知道自己至少需要跑几趟。
输入格式
在一行上输入四个整数 n , a , b , c ( 1 ≤ n , a , b , c ≤ 1 0 9 ) n,a,b,c(1 ≤ n,a,b,c≤ 10^9) n,a,b,c(1≤n,a,b,c≤109) 代表待装走的水量、三个桶的容量。
输出格式
在一行上输出一个整数,代表把 n n n 单位的水装完至少需要跑多少趟。
样例
输入:
4 2 2 1
输出:
2
题解
此题直接选取最大的桶来计算要跑几趟即可。时间复杂度 O ( 1 ) O(1) O(1)。
代码实现
C++:
#include<iostream>
using namespace std;
int main() {
int vol, b1, b2, b3;
cin >> vol >> b1 >> b2 >> b3;
int max_cap = max(b1, max(b2, b3));
int trips = vol / max_cap;
if(vol % max_cap != 0) trips++;
cout << trips << endl;
return 0;
}
Java:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int waterVol = scan.nextInt();
int bucket1 = scan.nextInt();
int bucket2 = scan.nextInt();
int bucket3 = scan.nextInt();
int maxSize = Math.max(bucket1, Math.max(bucket2, bucket3));
int tripCount = waterVol / maxSize;
if (waterVol % maxSize != 0) {
tripCount++;
}
System.out.println(tripCount);
}
}
Python:
def calc_trips():
water_vol, b_one, b_two, b_three = map(int, input().split())
max_size = max(b_one, b_two, b_three)
trips = water_vol // max_size
if water_vol % max_size:
trips += 1
return trips
if __name__ == "__main__":
print(calc_trips())
题目 2: 捉迷藏游戏
题目描述
小基®、小柯(B)和小兰(G)正在一个字符串上玩捉迷藏。他们所在的位置用对应字母表示,其他位置为空地(‘*’)或障碍(‘#’)。寻找方可以每秒移动一个位置,躲藏方不能移动。当寻找方移动到躲藏方的位置时,躲藏方被认为被找到。但是在过程中,双方均不可以移动到障碍上。
输入格式
在一行上输入一个仅由"*#RGB"组成的字符串 s ( 3 ≤ ∣ s ∣ ≤ 1 0 5 ) s(3 ≤ |s| ≤ 10^5) s(3≤∣s∣≤105),保证"RGB"各只出现一次。
输出格式
在一行上输出三个整数,代表小基、小柯和小兰作为寻找方时,能够获胜的最少时间;如果无法获胜,则直接输出 − 1 -1 −1。
样例
输入:
R***B**G
输出:
4 3 3
题解
直接模拟即可,找出三个人的位置,分别从三个人的位置出发,向字符串左右扫描寻找其他两人的位置并记录,碰见障碍则终止。时间复杂度 O ( n ) O(n) O(n)。
代码实现
C++:
#include<iostream>
using namespace std;
int find_min_time(string& s, int pos) {
int t1 = 1e9, t2 = 1e9;
auto check_pos = [&](int i, int dist) {
if(s[i] == 'R' || s[i] == 'G' || s[i] == 'B') {
if(t1 != 1e9) t2 = dist;
else t1 = dist;
}
};
for(int i = pos-1; i >= 0; i--) {
if(s[i] == '#') break;
check_pos(i, pos-i);
}
for(int i = pos+1; i < s.size(); i++) {
if(s[i] == '#') break;
check_pos(i, i-pos);
}
return (t1 == 1e9 && t2 == 1e9) ? -1 : min(t1, t2);
}
int main() {
string s;
cin >> s;
int r_time = -1, b_time = -1, g_time = -1;
for(int i = 0; i < s.size(); i++) {
if(s[i] == 'R') r_time = find_min_time(s, i);
if(s[i] == 'B') b_time = find_min_time(s, i);
if(s[i] == 'G') g_time = find_min_time(s, i);
}
cout << r_time << " " << b_time << " " << g_time << endl;
return 0;
}
Java:
import java.util.Scanner;
public class Main {
static int findMinTime(String str, int pos) {
int len = str.length();
int time1 = Integer.MAX_VALUE;
int time2 = Integer.MAX_VALUE;
// 向左搜索
for(int i = pos-1; i >= 0; i--) {
if(str.charAt(i) == '#') break;
if("RGB".indexOf(str.charAt(i)) >= 0) {
if(time1 != Integer.MAX_VALUE) {
time2 = pos - i;
} else {
time1 = pos - i;
}
}
}
// 向右搜索
for(int i = pos+1; i < len; i++) {
if(str.charAt(i) == '#') break;
if("RGB".indexOf(str.charAt(i)) >= 0) {
if(time1 != Integer.MAX_VALUE) {
time2 = i - pos;
} else {
time1 = i - pos;
}
}
}
return (time1 == Integer.MAX_VALUE && time2 == Integer.MAX_VALUE) ?
-1 : Math.min(time1, time2);
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String str = scan.next();
int[] times = new int[3];
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(c == 'R') times[0] = findMinTime(str, i);
if(c == 'B') times[1] = findMinTime(str, i);
if(c == 'G') times[2] = findMinTime(str, i);
}
System.out.printf("%d %d %d\n", times[0], times[1], times[2]);
}
}
Python:
def find_min_time(s: str, pos: int) -> int:
t1, t2 = float('inf'), float('inf')
def check_pos(i: int, dist: int):
nonlocal t1, t2
if s[i] in 'RGB':
if t1 != float('inf'):
t2 = dist
else:
t1 = dist
# 向左搜索
for i in range(pos-1, -1, -1):
if s[i] == '#': break
check_pos(i, pos-i)
# 向右搜索
for i in range(pos+1, len(s)):
if s[i] == '#': break
check_pos(i, i-pos)
return -1 if t1 == float('inf') and t2 == float('inf') else min(t1, t2)
def main():
s = input().strip()
times = [-1] * 3
for i, c in enumerate(s):
if c == 'R': times[0] = find_min_time(s, i)
elif c == 'B': times[1] = find_min_time(s, i)
elif c == 'G': times[2] = find_min_time(s, i)
print(*times)
if __name__ == "__main__":
main()
题目 3: 砖块合成
题目描述
小基有 a a a 个红砖、 b b b 个蓝砖和 c c c 个绿砖。每 x x x 个红砖可以合成 1 1 1 个蓝砖,每 y y y 个蓝砖可以合成 1 1 1 个绿砖。砖块只能正向合成,不能反向分解。一套砖块包含 1 1 1 个红砖、 1 1 1 个蓝砖和 1 1 1 个绿砖。请计算小基最多可以收集多少套砖块。
输入格式
第一行输入一个整数
T
(
1
≤
T
≤
1
0
5
)
T(1≤T≤10^5)
T(1≤T≤105) 代表数据组数。
每组数据输入五个整数
a
,
b
,
c
,
x
,
y
(
0
≤
a
,
b
,
c
≤
1
0
9
,
1
≤
x
,
y
≤
1
0
9
)
a,b,c,x,y(0≤a,b,c≤10^9,1≤x,y≤10^9)
a,b,c,x,y(0≤a,b,c≤109,1≤x,y≤109)。
输出格式
对于每组数据,输出一个整数,代表最多可以收集到的砖块套数。
样例
输入:
2
1 2 3 4 2
10 2 1 4 2
输出:
1
2
题解
使用二分查找,每次求出一个 mid 后,将大于 mid 的红砖和蓝砖全部合成,若最后三种砖数量均大于等于 mid,则将左端点置为 mid,否则将右端点置为 mid-1。时间复杂度 O ( T log n ) O(T\log n) O(Tlogn)。
代码实现
C++:
#include<iostream>
using namespace std;
typedef long long ll;
ll solve_case() {
ll red, blue, green, x_rate, y_rate;
cin >> red >> blue >> green >> x_rate >> y_rate;
ll left = 0, right = 1e9;
while(left < right) {
ll mid = (left + right + 1) / 2;
ll r = red, b = blue, g = green;
if(r > mid) {
ll conv = (r - mid) / x_rate;
r -= x_rate * conv;
b += conv;
}
if(b > mid) {
ll conv = (b - mid) / y_rate;
b -= y_rate * conv;
g += conv;
}
if(r >= mid && b >= mid && g >= mid)
left = mid;
else
right = mid - 1;
}
return left;
}
int main() {
int test_cnt;
cin >> test_cnt;
while(test_cnt--) cout << solve_case() << endl;
return 0;
}
Java:
import java.util.Scanner;
public class Main {
static long solveCase(Scanner scan) {
long redBrick = scan.nextLong();
long blueBrick = scan.nextLong();
long greenBrick = scan.nextLong();
long redRate = scan.nextLong();
long blueRate = scan.nextLong();
long left = 0, right = (long)1e9;
while(left < right) {
long mid = (left + right + 1) / 2;
long r = redBrick;
long b = blueBrick;
long g = greenBrick;
if(r > mid) {
long conv = (r - mid) / redRate;
r -= redRate * conv;
b += conv;
}
if(b > mid) {
long conv = (b - mid) / blueRate;
b -= blueRate * conv;
g += conv;
}
if(r >= mid && b >= mid && g >= mid)
left = mid;
else
right = mid - 1;
}
return left;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int testCount = scan.nextInt();
while(testCount-- > 0)
System.out.println(solveCase(scan));
}
}
Python:
def solve_case():
r_cnt, b_cnt, g_cnt, x_val, y_val = map(int, input().split())
left, right = 0, 10**9
while left < right:
mid = (left + right + 1) // 2
r, b, g = r_cnt, b_cnt, g_cnt
if r > mid:
conv = (r - mid) // x_val
r -= x_val * conv
b += conv
if b > mid:
conv = (b - mid) // y_val
b -= y_val * conv
g += conv
if r >= mid and b >= mid and g >= mid:
left = mid
else:
right = mid - 1
return left
def main():
for _ in range(int(input())):
print(solve_case())
if __name__ == "__main__":
main()
题目 4: 好数组问题
题目描述
小基有一个长度为 n n n 的数组 [ a 1 , a 2 , . . . , a n ] [a_1,a_2,...,a_n] [a1,a2,...,an]。他定义一个数组 x x x 是好的,当且仅当数组中所有数的最小公倍数 l c m lcm lcm 不存在于 x x x 中。小基希望从 a a a 中选择一个子序列,使得此子序列是好数组,并且他想知道子序列的最大长度。
输入格式
第一行输入一个整数
T
(
1
≤
T
≤
100
)
T(1≤T≤100)
T(1≤T≤100) 代表数据组数。
每组数据第一行输入一个整数
n
(
1
≤
n
≤
2000
)
n(1≤n≤2000)
n(1≤n≤2000)。
第二行输入
n
n
n 个整数
a
1
,
a
2
,
.
.
.
,
a
n
(
1
≤
a
i
≤
1
0
9
)
a_1,a_2,...,a_n(1≤a_i≤10^9)
a1,a2,...,an(1≤ai≤109)。
输出格式
对于每组数据,输出一个整数,代表可以选择的好子序列的最大长度。
样例
输入:
2
3
1 3 2
5
1 2 3 12 4
输出:
3
4
题解
如果一个数组中所有数的 lcm 在这个数组中,那这个数一定是最大的数。从贪心角度考虑,如果整个数组的 lcm 等于最大的数,就去删掉这个最大的数。时间复杂度 O ( T n log n ) O(T n \log n) O(Tnlogn)。
代码实现
C++:
#include<iostream>
#include<algorithm>
using namespace std;
long long gcd(long long a, long long b) {
return b ? gcd(b, a % b) : a;
}
long long lcm(long long a, long long b) {
return a / gcd(a, b) * b;
}
int solve_case() {
int n;
cin >> n;
vector<int> nums(n);
for(int i = 0; i < n; i++) cin >> nums[i];
sort(nums.begin(), nums.end());
long long curr_lcm = 1;
int max_len = 0;
for(int i = 0; i < n; i++) {
curr_lcm = lcm(curr_lcm, nums[i]);
if(curr_lcm > 1e9) return n;
if(curr_lcm > nums[i]) max_len = i + 1;
}
return max_len;
}
int main() {
int t;
cin >> t;
while(t--) cout << solve_case() << endl;
return 0;
}
Java:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static long gcd(long a, long b) {
return b == 0 ? a : gcd(b, a % b);
}
static long lcm(long a, long b) {
return a / gcd(a, b) * b;
}
static int solveCase(Scanner scan) {
int size = scan.nextInt();
int[] nums = new int[size];
for(int i = 0; i < size; i++)
nums[i] = scan.nextInt();
Arrays.sort(nums);
long currLcm = 1;
int maxLen = 0;
for(int i = 0; i < size; i++) {
currLcm = lcm(currLcm, nums[i]);
if(currLcm > 1_000_000_000) return size;
if(currLcm > nums[i]) maxLen = i + 1;
}
return maxLen;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int tests = scan.nextInt();
while(tests-- > 0)
System.out.println(solveCase(scan));
}
}
Python:
from math import gcd
from functools import reduce
def lcm(a, b):
return a * b // gcd(a, b)
def solve_case():
n = int(input())
nums = sorted(map(int, input().split()))
curr_lcm = 1
max_len = 0
for i, num in enumerate(nums):
curr_lcm = lcm(curr_lcm, num)
if curr_lcm > 10**9:
return n
if curr_lcm > num:
max_len = i + 1
return max_len
def main():
for _ in range(int(input())):
print(solve_case())
if __name__ == "__main__":
main()
题目 5: 图上游戏
题目描述
小基正在一张有向连通图上玩游戏。这张图包含 n n n 个点,第 i i i 个点的权值为 a i a_i ai,当从 i i i 移动到 N e x t i Next_i Nexti 时,游戏规则如下:
- 如果 a N e x t i > a i a_{Next_i} > a_i aNexti>ai,金币将增加 x x x
- 如果 a N e x t i ≤ a i a_{Next_i} ≤ a_i aNexti≤ai,金币将增加 y y y
小基会提出 q q q 次询问,每个询问从某个点 u u u 出发,移动不超过 k k k 步,最多能获得多少金币。
输入格式
第一行输入四个整数
n
,
q
,
x
,
y
(
1
≤
n
,
q
≤
2
×
1
0
5
,
−
1
0
6
≤
x
,
y
≤
1
0
6
)
n,q,x,y(1≤n,q≤2×10^5,-10^6≤x,y≤10^6)
n,q,x,y(1≤n,q≤2×105,−106≤x,y≤106)。
第二行输入
n
n
n 个整数
N
e
x
t
1
,
N
e
x
t
2
,
.
.
.
,
N
e
x
t
n
(
1
≤
N
e
x
t
i
≤
n
)
Next_1,Next_2,...,Next_n(1≤Next_i≤n)
Next1,Next2,...,Nextn(1≤Nexti≤n)。
第三行输入
n
n
n 个整数
a
1
,
a
2
,
.
.
.
,
a
n
(
1
≤
a
i
≤
1
0
6
)
a_1,a_2,...,a_n(1≤a_i≤10^6)
a1,a2,...,an(1≤ai≤106)。
接下来
q
q
q 行,每行输入两个整数
u
,
k
(
1
≤
u
≤
n
,
1
≤
k
≤
1
0
9
)
u,k(1≤u≤n,1≤k≤10^9)
u,k(1≤u≤n,1≤k≤109)。
输出格式
对于每次询问,输出一个整数,代表最多能获得的金币数量。
样例
输入:
4 5 -2 3
2 3 4 1
5 10 3 2
1 1
1 2
1 4
2 4
2 7
输出:
0
1
4
6
8
题解
使用倍增思想维护每个点走 2 j 2^j 2j 步的最大收益。时间复杂度 O ( n log n + q log k ) O(n\log n + q\log k) O(nlogn+qlogk)。
代码实现
C++:
#include<bits/stdc++.h>
using namespace std;
struct State {
long long sum, pre;
State(long long s = 0, long long p = 0): sum(s), pre(p) {}
};
State merge(State a, State b) {
return State(a.sum + b.sum, max(a.pre, a.sum + b.pre));
}
const int MAX_N = 200005;
const int MAX_LOG = 30;
pair<int, State> dp[MAX_N][MAX_LOG];
void init(int n, vector<int>& next, vector<int>& vals, int x, int y) {
for(int i = 1; i <= n; i++) {
dp[i][0].first = next[i-1];
int w = (vals[next[i-1]-1] > vals[i-1]) ? x : y;
dp[i][0].second = State(w, w);
}
for(int j = 1; j < MAX_LOG; j++) {
for(int i = 1; i <= n; i++) {
int v = dp[i][j-1].first;
dp[i][j] = {dp[v][j-1].first,
merge(dp[i][j-1].second, dp[v][j-1].second)};
}
}
}
long long query(int u, long long k) {
State res;
for(int i = MAX_LOG-1; i >= 0; i--) {
if(k & (1LL << i)) {
res = merge(res, dp[u][i].second);
u = dp[u][i].first;
}
}
return res.pre;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n, q, x, y;
cin >> n >> q >> x >> y;
vector<int> next(n), vals(n);
for(int i = 0; i < n; i++) cin >> next[i];
for(int i = 0; i < n; i++) cin >> vals[i];
init(n, next, vals, x, y);
while(q--) {
int u, k;
cin >> u >> k;
cout << query(u, k) << '\n';
}
return 0;
}
Java:
import java.util.*;
import java.io.*;
public class Main {
static class State {
long sum, pre;
State(long s, long p) {
sum = s;
pre = p;
}
}
static class Pair {
int next;
State state;
Pair(int n, State s) {
next = n;
state = s;
}
}
static final int MAX_LOG = 30;
static Pair[][] dp;
static State merge(State a, State b) {
return new State(
a.sum + b.sum,
Math.max(a.pre, a.sum + b.pre)
);
}
static void init(int n, int[] next, int[] vals, int x, int y) {
dp = new Pair[n+1][MAX_LOG];
for(int i = 1; i <= n; i++) {
int w = (vals[next[i-1]-1] > vals[i-1]) ? x : y;
dp[i][0] = new Pair(next[i-1], new State(w, w));
}
for(int j = 1; j < MAX_LOG; j++) {
for(int i = 1; i <= n; i++) {
int v = dp[i][j-1].next;
dp[i][j] = new Pair(
dp[v][j-1].next,
merge(dp[i][j-1].state, dp[v][j-1].state)
);
}
}
}
static long query(int u, long k) {
State res = new State(0, 0);
for(int i = MAX_LOG-1; i >= 0; i--) {
if((k & (1L << i)) != 0) {
res = merge(res, dp[u][i].state);
u = dp[u][i].next;
}
}
return res.pre;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int q = Integer.parseInt(st.nextToken());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
int[] next = new int[n];
int[] vals = new int[n];
st = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++)
next[i] = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++)
vals[i] = Integer.parseInt(st.nextToken());
init(n, next, vals, x, y);
StringBuilder sb = new StringBuilder();
while(q-- > 0) {
st = new StringTokenizer(br.readLine());
int u = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
sb.append(query(u, k)).append('\n');
}
System.out.print(sb);
}
}
Python:
class State:
def __init__(self, sum_val=0, pre_val=0):
self.sum = sum_val
self.pre = pre_val
def merge(a: State, b: State) -> State:
return State(
a.sum + b.sum,
max(a.pre, a.sum + b.pre)
)
def init_dp(n: int, next_arr: list, vals: list, x: int, y: int) -> list:
MAX_LOG = 30
dp = [[(0, State()) for _ in range(MAX_LOG)] for _ in range(n+1)]
for i in range(1, n+1):
w = x if vals[next_arr[i-1]-1] > vals[i-1] else y
dp[i][0] = (next_arr[i-1], State(w, w))
for j in range(1, MAX_LOG):
for i in range(1, n+1):
v = dp[i][j-1][0]
dp[i][j] = (
dp[v][j-1][0],
merge(dp[i][j-1][1], dp[v][j-1][1])
)
return dp
def query(dp: list, u: int, k: int) -> int:
res = State()
for i in range(29, -1, -1):
if k & (1 << i):
res = merge(res, dp[u][i][1])
u = dp[u][i][0]
return res.pre
def main():
n, q, x, y = map(int, input().split())
next_arr = list(map(int, input().split()))
vals = list(map(int, input().split()))
dp = init_dp(n, next_arr, vals, x, y)
for _ in range(q):
u, k = map(int, input().split())
print(query(dp, u, k))
if __name__ == "__main__":
main()

2339

被折叠的 条评论
为什么被折叠?



