小红书笔试 小红书笔试题 小红书 2026春招笔试真题解析
笔试时间:2026年3月18日
往年笔试合集:
第一题:冲突约束
题目
小红书生态团队在评论审核中,需要对得分接近的评论判定观点相近,这一判断逻辑可以帮助团队灵活的调整评论区的观点统一性/观点多样性。
现在,将模型简化如下:给定长度为 n 的整数数组 a 和一个整数 k。若 |a[i] - a[j]| ≤ k,则称 a[i] 与 a[j] 观点相近。
一次操作可以选择一对元素,并将其同时从数组中删除(数组长度减少 2)。
经过若干操作后,需要保证数组中不含任何观点相近的元素,且希望保留的元素数量尽可能多。
请你计算,经过若干操作后,最终保留下来的最大元素数量。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T (T ≥ 1) 代表数据组数,每组测试数据描述如下:
第一行输入两个整数 n 和 k (1 ≤ n ≤ 2×10⁵),表示数组长度、观点相近的阈值。
第二行输入 n 个整数 a[i] (|a[i]| ≤ 10⁹),表示数组元素。
除此之外,保证单个测试文件的 n 之和不超过 2×10⁵。
输出描述
对于每组测试数据,新起一行输出一个整数,表示最终保留下来的最大元素数量。
样例输入
2 5 2 1 2 4 7 9 4 0 1 1 2 5
样例输出
3 2
样例解释
对于第一组测试数据,保留 {1, 4, 7},我们可以证明这是最优的。
对于第二组测试数据,在 k=0 时,相等元素冲突,保留 {1, 5},我们可以证明这是最优的。
参考题解
解题思路:
利用贪心算法来寻找满足不冲突条件下的"最大独立集"。首先对整个数组进行升序排序,然后从左到右依次遍历,只要当前遍历到的元素与上一个决定保留的元素差值严格大于阈值 k(即两者不冲突),就贪心地将其加入保留集合。这种从左到右取最小可行值的策略,能保证在有限的数值范围内塞下尽可能多的不冲突元素,从而求出理论上最多能保留的个数。
其次,需要处理题目中"每次必须同时删除一对(两个)元素"的限制。这意味着最终被剔除的元素总数必须是偶数。因此,在贪心求出最多保留个数后,计算被淘汰的元素数量(数组总长度减去最多保留个数)。如果这个淘汰数量是奇数,说明剩余的元素无法完美两两组队删除,必须从保留的集合中再多牺牲掉一个元素,让被删除总数变成偶数。
C++:
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, k;
scanf("%d%d", &n, &k);
vector<int> a(n);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
sort(a.begin(), a.end());
int validCount = 0;
long long prev = -3000000000LL;
for (int i = 0; i < n; i++) {
if (a[i] - prev > k) {
validCount++;
prev = a[i];
}
}
if ((n - validCount) % 2 == 1) {
validCount--;
}
printf("%d\n", validCount);
}
return 0;
}
Java:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
if (reader.hasNextInt()) {
int testCases = reader.nextInt();
for (int t = 0; t < testCases; t++) {
int size = reader.nextInt();
int limit = reader.nextInt();
int[] elements = new int[size];
for (int idx = 0; idx < size; ++idx) {
elements[idx] = reader.nextInt();
}
Arrays.sort(elements);
int validCount = 0;
long previousVal = -3000000000L;
for (int idx = 0; idx < size; ++idx) {
if (elements[idx] - previousVal > limit) {
validCount++;
previousVal = elements[idx];
}
}
if ((size - validCount) % 2 == 1) {
validCount--;
}
System.out.println(validCount);
}
}
reader.close();
}
}
Python:
import sys
input = sys.stdin.readline
T = int(input())
for _ in range(T):
n, k = map(int, input().split())
a = list(map(int, input().split()))
a.sort()
valid_count = 0
prev = -3000000000
for x in a:
if x - prev > k:
valid_count += 1
prev = x
if (n - valid_count) % 2 == 1:
valid_count -= 1
print(valid_count)
第二题:小红书丝带AR特效
题目
在小红书"品牌创意工坊"中,营销人员可以为直播和短视频活动创建定制化丝带AR特效,结合品牌ID与礼盒包装场景,实现动态丝带动画。为了支撑亿级日活的前端渲染,后端需要在活动发布时预先计算并缓存所有可能的切割方案数,确保小程序组件和Web端秒级响应。
现有一根虚拟丝带长度为 n,可以将其分割成若干段或保持一整段不动,但是每段长度只能取整数 x、y 或 z 中的一个,且不允许任何长度为 x 的段后面直接跟随长度为 z 的段。
请对所有长度 i (1 ≤ i ≤ n),统计合法的切割方案数,供小红书前端组件批量加载与渲染。由于答案可能很大,请将答案对 10⁹+7 取模后输出。顺序不同视为不同方案。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T (T ≥ 1) 代表数据组数,每组测试数据描述如下:
在一行上输入四个整数 n, x, y, z (1 ≤ n ≤ 10⁶),代表最大丝带长度、可选分段长度 x, y, z。保证 x, y, z 两两互不相等。
除此之外,保证单个测试文件的 n 之和不超过 10⁶。
输出描述
对于每组测试数据,新起一行,输出 n 个整数,其中第 i 个数表示长度为 i 的丝带的合法分割方案数对 10⁹+7 取模的结果。
样例输入
2 5 1 2 3 4 1 2 3
样例输出
1 2 4 6 11 1 2 4 6
样例解释
在第一个样例中,当 n=5 时:
- i=1 时,仅有一种分割方案 {1};
- i=2 时,有 {1,1} 和 {2} 两种方案;
- i=3 时,有 {1,1,1}, {1,2}, {2,1}, {3} 共 4 种方案;
- i=4 时,按不带约束的方式共有 7 种方案,但其中 {1,3} 不合法,故为 6 种;
- i=5 时,合法方案共 11 种。
参考题解
解题思路:
采用动态规划。使用一个主数组 dpSum 记录到达每一个指定长度时的总合法方案数;同时,为了处理题目中"长度 x 后面不能直接跟 z"的特殊约束,额外使用一个辅助数组 stateX 来专门记录"以长度为 x 的段作为结尾"的方案数。
在状态转移过程中,对于任意长度 i,其合法方案数由最后一步的三种切割选择累加而成:如果最后切的是 x 或 y,其方案数分别直接继承自长度为 i-x 和 i-y 时的总方案数;如果最后切的是 z,则必须从长度为 i-z 的总方案数中,减去那些以 x 结尾的方案(即 stateX[i-z]),从而精准剔除掉"x 后面接 z"的不合法组合。最后将这三个分支的有效方案数相加并进行取模,即可递推得到答案。
C++:
#include <bits/stdc++.h>
using namespace std;
const int MODULO = 1000000007;
int main() {
int t;
scanf("%d", &t);
const int LIMIT = 1000005;
vector<int> stateX(LIMIT, 0);
vector<int> dpSum(LIMIT, 0);
while (t--) {
int len, x, y, z;
scanf("%d%d%d%d", &len, &x, &y, &z);
dpSum[0] = 1;
stateX[0] = 0;
for (int i = 1; i <= len; i++) {
int pickX = (i >= x) ? dpSum[i - x] : 0;
int pickY = (i >= y) ? dpSum[i - y] : 0;
int pickZ = 0;
if (i >= z) {
pickZ = dpSum[i - z] - stateX[i - z];
if (pickZ < 0) pickZ += MODULO;
}
stateX[i] = pickX;
long long currentTotal = (long long)pickX + pickY + pickZ;
dpSum[i] = (int)(currentTotal % MODULO);
printf("%d", dpSum[i]);
if (i < len) printf(" ");
}
printf("\n");
}
return 0;
}
Java:
import java.util.Scanner;
public class Main {
static final int MODULO = 1000000007;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
if (!input.hasNextInt()) {
return;
}
int t = input.nextInt();
int limit = 1000005;
int[] stateX = new int[limit];
int[] dpSum = new int[limit];
for (int k = 0; k < t; k++) {
int len = input.nextInt();
int x = input.nextInt();
int y = input.nextInt();
int z = input.nextInt();
dpSum[0] = 1;
stateX[0] = 0;
for (int idx = 1; idx <= len; idx++) {
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
