网易笔试 网易春招实习 网易笔试真题解析 0402
笔试时间:2026年4月2日
往年笔试合集:
第一题:沙场点兵
题目
在网易旗舰级武侠游戏《逆水寒》的"宋辽边境"战场玩法中,宋辽两军正隔河对峙。
辽军统帅为了挫败我方士气,摆下了"连环阵":他们派出了 n 支精锐的先锋小队,并公开了这 n 支小队出战的先后顺序以及每一支小队的"战力值"。
作为宋军的战术指挥官,你手下同样拥有 n 支蓄势待发的铁骑小队,每支小队的"战力值"你也了如指掌。根据战场规则,两军将进行 n 轮一对一的"阵前对决":
每一轮,双方各派出一支小队进行厮杀;战力值较高的小队将全歼对手并获胜(积 1 分);若战力值相同,由于辽军占据地利,判定辽军获胜(宋军积 0 分,辽军积 1 分)。
战国时,齐威王与田忌赛马的故事广为人知,你也想成为如田忌一般的智将,带领你麾下的将士赢得胜利。请判断,是否存在一种排兵布阵的策略,使得我军最终的胜场数严格大于辽军的胜场数?
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T 表示演练的数据组数。每组测试数据描述如下:
- 第一行一个整数 n(n 为奇数),表示双方派出的小队数量。
- 第二行包含 n 个整数,表示我军(宋军)每支小队的战力值。
- 第三行包含 n 个整数,表示敌军(辽军)的出战顺序及其战力值。
保证所有测试中 n 的总和不超过 2 × 10^5。
输出描述
输出 T 行。对每组数据,若通过合理排兵布阵能使得我军胜场数 > 败场数,输出 YES;否则输出 NO。
样例输入
2 5 2 5 7 1 6 3 5 6 2 7 3 3 3 3 3 3 3
样例输出
YES NO
样例说明
对于第一组测试数据,一种最佳出兵顺序如下:
- 第一阵:派战力 2 迎战辽军 2(因相同,辽胜)
- 第二阵:派战力 5 迎战辽军 3(宋胜)
- 第三阵:派战力 6 迎战辽军 5(宋胜)
- 第四阵:派战力 7 迎战辽军 6(宋胜)
- 第五阵:派战力 1 迎战辽军 7(辽胜)
最终宋军 3 胜 2 负,大破辽军,输出 YES。
参考题解
解题思路:
该问题本质上是"田忌赛马"贪心策略的变体。为了获得尽可能多的胜场,首先将双方的战力值数组进行升序排序。通过双指针贪心法,尝试用我方当前最弱的兵力去对抗敌方最弱的兵力:
- 如果能赢,则匹配这对组合并增加胜场;
- 如果不能赢(即我方最弱兵力小于或等于敌方最弱兵力),则该兵力无法战胜敌方任何剩余兵力,应将其消耗掉,转而使用我方后续更强的兵力尝试匹配。
由于题目给出 n 为奇数,且要求胜场数严格大于败场数,因此最终只需判断最大胜场数是否超过 n/2(即至少达到 (n+1)/2 场)即可判定为 YES。
C++:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> song(n), liao(n);
for (int i = 0; i < n; i++) cin >> song[i];
for (int i = 0; i < n; i++) cin >> liao[i];
sort(song.begin(), song.end());
sort(liao.begin(), liao.end());
int victories = 0;
int enemyPtr = 0;
for (int i = 0; i < n; i++) {
if (song[i] > liao[enemyPtr]) {
victories++;
enemyPtr++;
}
}
cout << (victories > n / 2 ? "YES" : "NO") << "\n";
}
return 0;
}
Java:
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String firstLine = reader.readLine();
if (firstLine == null) return;
int testCases = Integer.parseInt(firstLine.trim());
PrintWriter out = new PrintWriter(System.out);
while (testCases-- > 0) {
int totalCount = Integer.parseInt(reader.readLine().trim());
long[] songArmy = new long[totalCount];
long[] liaoArmy = new long[totalCount];
StringTokenizer st1 = new StringTokenizer(reader.readLine());
for (int i = 0; i < totalCount; i++) {
songArmy[i] = Long.parseLong(st1.nextToken());
}
StringTokenizer st2 = new StringTokenizer(reader.readLine());
for (int i = 0; i < totalCount; i++) {
liaoArmy[i] = Long.parseLong(st2.nextToken());
}
Arrays.sort(songArmy);
Arrays.sort(liaoArmy);
int victories = 0;
int enemyPtr = 0;
for (int ourPtr = 0; ourPtr < totalCount; ourPtr++) {
if (songArmy[ourPtr] > liaoArmy[enemyPtr]) {
victories++;
enemyPtr++;
}
}
if (victories > totalCount / 2) {
out.println("YES");
} else {
out.println("NO");
}
}
out.flush();
}
}
Python:
import sys
input = sys.stdin.readline
def main():
T = int(input())
out = []
for _ in range(T):
n = int(input())
song = sorted(map(int, input().split()))
liao = sorted(map(int, input().split()))
victories = 0
enemy_ptr = 0
for s in song:
if s > liao[enemy_ptr]:
victories += 1
enemy_ptr += 1
out.append("YES" if victories > n // 2 else "NO")
sys.stdout.write('\n'.join(out) + '\n')
main()
第二题:背包排序
题目
玩家小 A 现在有一个 n × m 格子的背包(n 为高,m 为宽),有 k 个物品,先按排序算法把物品进行排序,然后根据排序后的物品依次放入背包。
在放入背包时,优先选择行数最小的位置进行放置,其次选择列数最小的位置。如果当前行无法容纳物品,则继续查找下一行。如果整个背包都无法放下该物品,则跳过该物品。
最后输出背包是否放得下所有物品,并输出当前背包状态,用 id 表示当前背包格子是什么物品,如果当前格子没有物品输出 0。
每个物品都包含以下这些属性:
- id:物品唯一 ID,每个物品各不相同。
- height, width:物品占用的格子数(height 为高,width 为宽)。物品不可以旋转放入背包。
- quality:物品的品质。数值越大品质越高。
- type:物品的种类。
排序规则如下:
- 优先按照 type 排序:
"equip" < "weapon" < "item" < "other" - 品质高的优先
- id 小的优先
输入描述
第一行包含三个整数 n、m、k,分别表示背包的高、背包的宽、物品的数量。
接下来 k 行,每行包含四个整数 id、height、width、quality,以及一个字符串 type(type ∈ {"equip", "weapon", "item", "other"}),为物品包含的属性。
输出描述
第一行包含一个字符串 "YES" 表示背包可以放下所有物品,"NO" 表示有的物品放不进去背包。
接下来 n 行,每行包含 m 个整数,表示当前格子放着的物品 id,如果当前格子没有物品则输出 0。
样例输入 1
4 3 3 1 1 3 7 other 2 3 1 2 equip 3 2 2 4 other
样例输出 1
YES 2 3 3 2 3 3 2 0 0 1 1 1
说明: 排序后顺序:2、3、1。按顺序放入即可。
样例输入 2
4 4 6 6 2 1 3 weapon 1 2 3 1 equip 3 2 1 4 item 5 3 3 3 weapon 2 2 2 3 other 4 2 1 3 item
样例输出 2
NO 1 1 1 6 1 1 1 6 3 4 2 2 3 4 2 2
参考题解
解题思路:
该程序采用贪心算法结合自定义排序规则。首先根据题目要求的优先级(种类权重 > 品质降序 > ID 升序)对所有物品进行预排序。随后遍历排序后的物品列表,在二维网格中按照"从上到下、从左到右"的顺序寻找第一个能够容纳该物品尺寸的空置区域。一旦找到合法位置,立即将其放置并填充 ID。若遍历整个网格均无法放置,则跳过该物品并标记最终状态为失败(NO)。
C++:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
struct Product {
int sn, rLen, cLen, score, level;
string category;
};
int typeLevel(const string& cat) {
if (cat == "equip") return 1;
if (cat == "weapon") return 2;
if (cat == "item") return 3;
return 4; // other
}
bool cmp(const Product& a, const Product& b) {
if (a.level != b.level) return a.level < b.level;
if (a.score != b.score) return a.score > b.score;
return a.sn < b.sn;
}
bool checkSpace(vector<vector<int>>& board, int x, int y, int h, int w) {
for (int i = x; i < x + h; i++)
for (int j = y; j < y + w; j++)
if (board[i][j] != 0) return false;
return true;
}
void markMatrix(vector<vector<int>>& board, int x, int y, int h, int w, int val) {
for (int i = x; i < x + h; i++)
for (int j = y; j < y + w; j++)
board[i][j] = val;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int rowMax, colMax, total;
cin >> rowMax >> colMax >> total;
vector<Product> list(total);
for (int i = 0; i < total; i++) {
cin >> list[i].sn >> list[i].rLen >> list[i].cLen >> list[i].score >> list[i].category;
list[i].level = typeLevel(list[i].category);
}
sort(list.begin(), list.end(), cmp);
vector<vector<int>> mat(rowMax, vector<int>(colMax, 0));
bool success = true;
for (const auto& p : list) {
bool placed = false;
// 优先遍历行,其次遍历列
for (int i = 0; i <= rowMax - p.rLen && !placed; i++) {
for (int j = 0; j <= colMax - p.cLen; j++) {
if (checkSpace(mat, i, j, p.rLen, p.cLen)) {
markMatrix(mat, i, j, p.rLen, p.cLen, p.sn);
placed = true;
break;
}
}
}
if (!placed) success = false;
}
cout << (success ? "YES" : "NO") << "\n";
for (int i = 0; i < rowMax; i++) {
for (int j = 0; j < colMax; j++) {
cout << mat[i][j] << (j == colMax - 1 ? "" : " ");
}
cout << "\n";
}
return 0;
}
Java:
import java.util.*;
import java.io.*;
public class Main {
static class Product implements Comparable<Product> {
int sn, rLen, cLen, score, level;
String category;
public Product(int sn, int rLen, int cLen, int score, String category) {
this.sn = sn;
this.rLen = rLen;
this.cLen = cLen;
this.score = score;
this.category = category;
// 映射类型权重
switch (category) {
case "equip": this.level = 1; break;
case "weapon": this.level = 2; break;
case "item": this.level = 3; break;
default: this.level = 4; break;
}
}
@Override
public int compareTo(Product other) {
if (this.level != other.level) return Integer.compare(this.level, other.level);
if (this.score != other.score) return Integer.compare(other.score, this.score);
return Integer.compare(this.sn, other.sn);
}
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
if (!cin.hasNextInt()) return;
int rowMax = cin.nextInt();
int colMax = cin.nextInt();
int total = cin.nextInt();
List<Product> cargoList = new ArrayList<>();
for (int i = 0; i < total; i++) {
cargoList.add(new Product(cin.nextInt(), cin.nextInt(), cin.nextInt(),
cin.nextInt(), cin.next()));
}
Collections.sort(cargoList);
int[][] mat = new int[rowMax][colMax];
boolean success = true;
for (Product p : cargoList) {
boolean isPlaced = false;
// 优先遍历行,其次遍历列
for (int i = 0; i <= rowMax - p.rLen; i++) {
for (int j = 0; j <= colMax - p.cLen; j++) {
if (checkSpace(mat, i, j, p.rLen, p.cLen)) {
markMatrix(mat, i, j, p.rLen, p.cLen, p.sn);
isPlaced = true;
break;
}
}
if (isPlaced) break;
}
if (!isPlaced) success = false;
}
System.out.println(success ? "YES" : "NO");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rowMax; i++) {
for (int j = 0; j < colMax; j++) {
sb.append(mat[i][j]).append(j == colMax - 1 ? "" : " ");
}
sb.append("\n");
}
System.out.print(sb.toString());
}
private static boolean checkSpace(int[][] board, int x, int y, int h, int w) {
for (int i = x; i < x + h; i++) {
for (int j = y; j < y + w; j++) {
if (board[i][j] != 0) return false;
}
}
return true;
}
private static void markMatrix(int[][] board, int x, int y, int h, int w, int val) {
for (int i = x; i < x + h; i++) {
for (int j = y; j < y + w; j++) {
board[i][j] = val;
}
}
}
}
Python:
import sys
def main():
data = sys.stdin.read().split()
idx = 0
rowMax = int(data[idx]); idx += 1
colMax = int(data[idx]); idx += 1
total = int(data[idx]); idx += 1
type_level = {"equip": 1, "weapon": 2, "item": 3, "other": 4}
products = []
for _ in range(total):
sn = int(data[idx]); idx += 1
rLen = int(data[idx]); idx += 1
cLen = int(data[idx]); idx += 1
score = int(data[idx]); idx += 1
category = data[idx]; idx += 1
level = type_level.get(category, 4)
# 排序键:(type权重升序, 品质降序, id升序)
products.append((level, -score, sn, rLen, cLen))
products.sort()
mat = [[0] * colMax for _ in range(rowMax)]
success = True
def check_space(x, y, h, w):
for i in range(x, x + h):
for j in range(y, y + w):
if mat[i][j] != 0:
return False
return True
def mark_matrix(x, y, h, w, val):
for i in range(x, x + h):
for j in range(y, y + w):
mat[i][j] = val
for level, neg_score, sn, rLen, cLen in products:
placed = False
# 优先遍历行,其次遍历列
for i in range(rowMax - rLen + 1):
if placed:
break
for j in range(colMax - cLen + 1):
if check_space(i, j, rLen, cLen):
mark_matrix(i, j, rLen, cLen, sn)
placed = True
break
if not placed:
success = False
out = ["YES" if success else "NO"]
for i in range(rowMax):
out.append(" ".join(str(mat[i][j]) for j in range(colMax)))
sys.stdout.write('\n'.join(out) + '\n')
main()
第三题:不朽荣光
题目
在《永劫无间》的决赛圈中,作为仅存的侠客之一,你正处于"聚窟洲"的一处狭长索桥上与其余敌方侠客对峙。
此时"暗域"(毒圈)已经严重蔓延,索桥的左端(坐标 ≤ 0)与右端(坐标 ≥ L)均已被高浓度的暗域覆盖,任何侠客一旦进入暗域范围就会因体力耗尽被瞬间淘汰。
令索桥的安全区域左侧边缘对应坐标 0,右侧边缘对应坐标 L。当前桥上还有 n 名敌方侠客,其初始坐标为 x_i,同一位置上可能有多名侠客,但均满足 0 < x_i < L,即暂时处于安全区内。
你捡到了一把金色品质的"火炮",并装备了稀有魂玉"连珠·反弹"。你可以向索桥上任意一个整数坐标点 p 发射一枚具有强力冲击波的炮弹,产生如下效果:
- 命中:如果某名敌方侠客当前坐标恰好为 p,则被炮弹直接命中造成巨额伤害淘汰;
- 左击退:如果某名敌方侠客当前坐标为 x 且 x < p,则会被爆炸气浪向左震飞 r 个单位,变为坐标 x - r;
- 右击退:如果某名敌方侠客当前坐标为 x 且 x > p,则会被爆炸气浪向右震飞 r 个单位,变为坐标 x + r。
当敌方侠客的坐标被震飞至 ≤ 0 或 ≥ L 时,就会跌入暗域被淘汰。
为了拿下"不朽荣光"成就(在另外两名队友已经阵亡的情况下,独自存活至少 1 分钟并最终获胜),你需要计算至少发射多少次炮弹,才能将所有敌方侠客淘汰?每次开火前,你都可以根据当前幸存敌人的位置,重新选择最优的落点 p。
输入描述
- 第一行输入三个整数 n、L、r,分别表示敌方侠客数量、索桥安全区长度与震飞距离;
- 第二行输入 n 个整数 x_i,表示初始时每名敌方侠客的坐标。
样例输入 1
3 10 2 3 5 9
样例输出 1
2
说明: 一种最优策略:第一次瞄准 5 处开火,直接淘汰坐标 5 的敌人,其余敌人被震飞至坐标 1(3-2,存活)和 11(9+2,掉入暗域淘汰);第二次瞄准 1 处开火,淘汰剩余敌人。
样例输入 2
5 20 3 2 6 9 12 17
样例输出 2
2
说明: 一种最优策略:第一次瞄准 9 处开火,直接淘汰坐标 9 的敌人,其余被震飞至 -1、3、15、20,其中 -1 和 20 触发暗域淘汰;第二次瞄准 3 处开火,直接淘汰坐标 3 的敌人,另一名被震飞至 18(15+3,掉入暗域淘汰)。
参考题解
解题思路:
本题采用排序去重 + 二分答案的算法思路。因为发射的炮弹越多,越容易淘汰所有敌人(结果具有单调性),所以我们可以通过二分查找来确定最少的射击次数 k。同一位置的敌人受气浪影响完全一致,因此预先进行去重处理。
在验证 k 次射击是否足够时,采用贪心策略:从左到右遍历敌人,对于当前敌人,贪心地假设前面已经不得不消耗的 need 次射击都在其左侧(产生向右的推力),而剩余的 (k - need) 次射击全在其右侧(产生向左的推力)。如果在这种最有利于将其向左震飞的极限情况下,该敌人仍留在安全区内(0 < 最终位置 < L),则说明必须额外消耗一次射击来处理他,令 need 加 1。若中途 need 超过了 k,则说明 k 发炮弹不够。
核心递推公式:pos = x + (2 * need - k) * r
C++:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
ll L, r;
vector<ll> a;
// 检查给定的射击总次数 k 是否足够
bool check(ll k) {
ll need = 0; // 记录必须使用的直接/左侧射击次数
for (ll x : a) {
// 假设已用的 need 次射击都在左侧,剩下的 (k - need) 次都在右侧
ll pos = x + (2LL * need - k) * r;
// 如果在此极限情况下仍处于安全区内,则必须额外开一炮
if (pos > 0 && pos < L) {
need++;
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
查看11道真题和解析