小红书笔试 小红书 0325 春招实习笔试真题
笔试时间:2026年3月25日
往年笔试合集:
第一题:乱序数据解析
题目
小红书数据库中有用户编号、用户名称和用户经验三个字段,其中:
- 用户编号为 1 到 10^9 间的整数,且唯一;
- 用户名称为长度不超过 10 的非空字符串,且仅由小写字母构成;
- 用户经验为 1 到 10^9 间的浮点数。
现在,你已经获取到了 n 条用户数据,每一条用户数据由:用户编号、用户名称、用户经验三个部分组成,但顺序是混乱的。请按照:用户编号从小到大排序并将排序后的用户数据按照:用户编号、用户名称、用户经验的顺序输出。
输入描述
输入一个整数 n (1≤n≤10^5),表示用户数据的数量。此后 n 行,第 i 行依次输入以下三个部分表示第 i 条用户数据(不保证某个部分一定在前,即部分间的顺序是乱序的;各部分之间用空格分隔):
- 一个整数 xi (1≤xi≤10^9),表示用户编号;
- 一个长度仅由小写字母构成的字符串 si (1≤length(si)≤10),表示用户名称;
- 一个小数位数为两位的浮点数 ci (0≤ci≤10^9),表示用户经验。
输出描述
一共 n 行,第 i 行依次输出用户编号第 i 小的用户编号、用户名称和用户经验,用空格分隔。
样例输入
3 xhs 12 106.70 0.00 abc 11 6 xhs 666.66
样例输出
6 xhs 666.66 11 abc 0.00 12 xhs 106.70
参考题解
解题思路
由于每条数据的三个字段输入顺序是随机的,但它们各自具有严格的数据类型排他性:由小写字母构成的字符串必是"用户名称",包含小数点的浮点型格式必是"用户经验",剩下的纯数字构成的必定是"用户编号"。在读入时,利用字符串首字母范围和是否包含 . 这两个特征,精准拦截并分类各个字段,将它们打包存入列表后,直接以用户编号为关键字进行升序排序并输出即可。
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<tuple<long long, string, string>> userList;
for (int i = 0; i < n; i++) {
long long userId = 0;
string userName = "", userExp = "";
for (int j = 0; j < 3; j++) {
string token;
cin >> token;
if (token[0] >= 'a' && token[0] <= 'z') {
userName = token;
} else if (token.find('.') != string::npos) {
userExp = token;
} else {
userId = stoll(token);
}
}
userList.emplace_back(userId, userName, userExp);
}
sort(userList.begin(), userList.end());
for (auto& [id, name, exp] : userList) {
cout << id << " " << name << " " << exp << "\n";
}
return 0;
}
Java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
long[] ids = new long[n];
String[] names = new String[n];
String[] exps = new String[n];
for (int i = 0; i < n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < 3; j++) {
String token = st.nextToken();
if (token.charAt(0) >= 'a' && token.charAt(0) <= 'z') {
names[i] = token;
} else if (token.contains(".")) {
exps[i] = token;
} else {
ids[i] = Long.parseLong(token);
}
}
}
Integer[] indices = new Integer[n];
for (int i = 0; i < n; i++) indices[i] = i;
Arrays.sort(indices, (a, b) -> Long.compare(ids[a], ids[b]));
StringBuilder sb = new StringBuilder();
for (int idx : indices) {
sb.append(ids[idx]).append(" ").append(names[idx]).append(" ").append(exps[idx]).append("\n");
}
System.out.print(sb);
}
}
Python
import sys
def solve():
input_data = sys.stdin.read().split()
if not input_data:
return
n = int(input_data[0])
idx = 1
user_list = []
for _ in range(n):
user_id = 0
user_name = ""
user_exp = ""
for _ in range(3):
token = input_data[idx]
idx += 1
if 'a' <= token[0] <= 'z':
user_name = token
elif '.' in token:
user_exp = token
else:
user_id = int(token)
user_list.append((user_id, user_name, user_exp))
user_list.sort(key=lambda user: user[0])
out = [f"{user[0]} {user[1]} {user[2]}" for user in user_list]
print('\n'.join(out))
if __name__ == '__main__':
solve()
第二题:无限轮互评模拟
题目
现在有 n 条 Plog 在首页上排成一列,队尾在下侧,队头在上侧。用长度为 n 的 01 串 s=s1s2…sn 表示这条队列,其中:
- 若 si=1,则第 i 条 Plog 属于美食;
- 若 si=0,则第 i 条 Plog 属于旅行。
一共会进行无限轮互评操作,每一轮:
- 所有 Plog 的拥有者同时向队头(右侧)互评;
- 互评只会影响每条 Plog 右侧的第一个异属性 Plog,如果右侧没有异属性 Plog,则不会产生互评操作;
- 每轮所有互评动作并行计算,然后一次性将所有已经有评论的 Plog 移出,形成新队列再进入下一轮;同一条 Plog 在一轮可能收获多条评价。
显然,无限进行下去,终究会出现不再有互评发生的情况。求整个过程中共有多少条 Plog 收获评价。
输入描述
第一行输入一个整数 n (1≤n≤10^5),表示 Plog 数量。第二行输入一个长度为 n 且只由字符 0 和 1 构成的字符串 s,表示 Plog 的属性分布,其中 si 为从左向右第 i 条 Plog 的属性。
输出描述
输出一个整数,表示所有互评结束后共有多少条 Plog 收获评价。
样例输入1
5 11101
样例输出1
2
样例说明1
在这个样例中:第一轮,第三条(1)评论第四条(0),第四条(0)评论第五条(1),共 2 条 Plog 收获评论;剩余前三条 Plog 拼接为 "111",此时剩下的全是美食 Plog,不再发生互评现象。
样例输入2
10 1100010101
样例输出2
8
样例说明2
"1100010101" → "1100" → "110" → "11" 一共有 8 条 Plog 被评论。
参考题解
解题思路
首先将连续的同属性 Plog 压缩成若干个长度块,最左侧的第一个块视为"绝对安全区",后续的块按照索引奇偶性交替扮演"异属性(敌人)"和"同属性(友军)"的角色。在从左到右遍历的过程中,将奇数索引的异属性长度不断累加,代表"挡在前面的敌人";当遇到偶数索引的同属性块时,让它与前面累积的敌人互相消耗(同属性多则余下部分并入安全区,异属性多则同属性被全部吞噬)。最终,用 Plog 总长度减去存活在安全区的总长度,就是整个过程中发生过互评(被消耗掉)的 Plog 数量。
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
string s;
cin >> s;
if (n <= 1) {
cout << 0 << endl;
return 0;
}
// 将连续相同的字符压缩为长度块
vector<int> blockLengths;
char currentChar = s[0];
int currentCount = 1;
for (int i = 1; i < n; i++) {
if (s[i] == currentChar) {
currentCount++;
} else {
blockLengths.push_back(currentCount);
currentChar = s[i];
currentCount = 1;
}
}
blockLengths.push_back(currentCount);
if (blockLengths.size() <= 1) {
cout << 0 << endl;
return 0;
}
int safeCount = blockLengths[0]; // 第一块必定是安全的起始块
int pendingEnemies = 0; // 累积的异属性数量
for (int i = 1; i < (int)blockLengths.size(); i++) {
if (i % 2 != 0) {
// 奇数索引:异属性块,敌人数量增加
pendingEnemies += blockLengths[i];
} else {
// 偶数索引:同属性块,与累积的敌人发生抵消
if (blockLengths[i] > pendingEnemies) {
safeCount += blockLengths[i] - pendingEnemies;
pendingEnemies = 0;
} else {
pendingEnemies -= blockLengths[i];
}
}
}
cout << n - safeCount << endl;
return 0;
}
Java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
String s = br.readLine().trim();
if (n <= 1) {
System.out.println(0);
return;
}
// 将连续相同的字符压缩为长度块
List<Integer> blockLengths = new ArrayList<>();
char currentChar = s.charAt(0);
int currentCount = 1;
for (int
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
