【春招笔试】2025.05.18蚂蚁算法岗笔试真题改编题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题(建议用时:90分钟/套)
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线80+套真题改编解析,后续会持续更新的
春秋招合集 -> 互联网必备刷题宝典🔗
题目一:平衡花园设计
1️⃣:枚举可能的差值常数C(范围0到n)
2️⃣:对每个C值,计算将每个位置调整为i+C或i-C的最小代价
3️⃣:取所有可能C值中的最小总代价
难度:中等
这道题目要求调整数组使得所有位置的值与位置下标的差的绝对值相等。关键是枚举所有可能的差值常数C,并计算每种情况的最小调整代价。时间复杂度为O(n²),在给定数据范围内可以高效求解。
题目二:图像聚类分析系统
1️⃣:将三维图像数据重组为二维矩阵(样本×特征)
2️⃣:使用PCA算法将数据从多通道降维到二维空间
3️⃣:使用K-Means算法对降维后的数据进行聚类分析
4️⃣:将聚类结果重组为原始图像尺寸并输出
难度:中等
这道题目结合了数据预处理、降维和聚类分析技术,要求对图像数据进行有效的处理。通过PCA降维减少数据复杂度,再使用K-Means进行聚类,可以发现图像中像素的自然分组。时间复杂度主要取决于图像大小和通道数,但在给定的数据范围内是可以高效求解的。
题目三:回文密码构造
1️⃣:理解长度为3的回文子序列形成规则
2️⃣:使用递推公式计算添加新字符后产生的新回文数量
3️⃣:逐位构造01串,确保每个前缀的回文权值符合要求
难度:中等偏难
这道题目要求根据前缀回文权值要求构造01字符串。关键在于理解当添加一个字符时,如何影响长度为3的回文子序列数量。通过维护已有字符的数量和位置和,我们可以O(n)时间复杂度内构造出答案或判断无解。
01. 平衡花园设计
问题描述
小柯是一位热爱园艺的景观设计师。她最近接到了一个特殊的花园设计项目,这个花园有 个花坛排成一排,编号从
到
。每个花坛目前种有
株植物。
为了使花园更加美观,小柯希望调整每个花坛的植物数量,使得所有花坛都满足一个特殊的"和谐条件":对于每个花坛,其植物数量与花坛编号之间的差的绝对值都相等。
每次调整操作可以为任意一个花坛增加或减少一株植物,每次操作的代价为1。小柯想知道,最少需要多少次操作才能使所有花坛满足和谐条件。
输入格式
第一行一个整数 ,表示花坛的数量。
第二行 个整数,第
个为
,表示第
个花坛的植物数量。
输出格式
一个整数,表示使所有花坛满足和谐条件的最少操作次数。
样例输入
3
3 2 1
3
1 2 3
样例输出
2
0
样例1 | 可以将花坛调整为[1,2,3],这样每个花坛的植物数量与其编号的差的绝对值都为0。需要进行2次操作:将第1个花坛的植物从3减少到1,将第3个花坛的植物从1增加到3。 |
样例2 | 原始状态已经满足和谐条件,每个花坛的植物数量等于其编号,差的绝对值为0,不需要任何操作。 |
数据范围
题解
这道题目看起来很直观:我们需要调整每个花坛的植物数量,使得所有 的值相等。那么问题的关键是,这个相等的值应该是多少?
首先,我们发现这个相等的值(我们称它为 )可以是任意非负整数。当
时,意味着每个花坛的植物数量恰好等于它的编号;当
时,意味着每个花坛的植物数量要么比编号多
,要么比编号少
。
对于每个可能的 值,我们可以计算将当前数组调整为满足条件所需的操作次数。具体来说,对于每个位置
,我们有两种可能的目标值:
或
。我们应该选择与当前值
差距较小的那个,以最小化操作次数。
我们需要枚举所有可能的 值(从0到n),计算每种情况下的总操作次数,然后取最小值。由于
最大为1000,枚举所有可能的
值是可行的。
时间复杂度为 ,其中
是花坛的数量。对于每个
值(最多
种可能),我们需要遍历整个数组(
个元素)计算操作次数。
参考代码
- Python
import sys
input = lambda:sys.stdin.readline().strip()
def solve():
# 读取输入
n = int(input())
a = [0] + list(map(int, input().split())) # 下标从1开始
# 枚举所有可能的 C 值
ans = float('inf')
for c in range(n + 1):
cost = 0
for i in range(1, n + 1):
# 计算调整到 i+c 或 i-c 所需的操作次数
opt1 = abs(a[i] - (i + c))
opt2 = abs(a[i] - (i - c))
cost += min(opt1, opt2)
ans = min(ans, cost)
return ans
print(solve())
- Cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<ll> a(n+1);
for (int i = 1; i <= n; ++i)
cin >> a[i];
ll ans = LLONG_MAX;
for (ll c = 0; c <= n; ++c) {
ll cost = 0;
for (int i = 1; i <= n; ++i) {
ll v1 = i + c;
ll v2 = i - c;
ll c1 = abs(a[i] - v1);
ll c2 = abs(a[i] - v2);
cost += min(c1, c2);
}
ans = min(ans, cost);
}
cout << ans;
return 0;
}
- Java
import java.io.*;
import java.util.*;
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());
long[] arr = new long[n+1];
String[] line = br.readLine().split(" ");
for (int i = 1; i <= n; i++) {
arr[i] = Long.parseLong(line[i-1]);
}
long ans = Long.MAX_VALUE;
for (int c = 0; c <= n; c++) {
long cost = 0;
for (int i = 1; i <= n; i++) {
long v1 = i + c;
long v2 = i - c;
long c1 = Math.abs(arr[i] - v1);
long c2 = Math.abs(arr[i] - v2);
cost += Math.min(c1, c2);
}
ans = Math.min(ans, cost);
}
System.out.println(ans);
}
}
02. 图像聚类分析系统
问题描述
小基是一家计算机视觉公司的研究员,正在开发一个图像分析系统。她需要实现一个图像处理模块,该模块能够对输入的图像数据进行降维和聚类分析,以便于后续的图像理解和处理。
具体来说,她需要完成以下任务:
- 读取输入的三维列表,表示图像数据(多个通道,如彩色图像)。
- 使用
(主成分分析)对图像数据进行降维,将图像数据从多通道降到二维空间。
- 使用
算法对降维后的数据进行聚类,将像素点分为3个类别。
- 输出每个像素点的聚类标签。
输入格式
输入为一个三维列表,表示图像数据的像素值。
输出格式
输出为一个二维列表的每一行,表示每个像素点的聚类标签,从 开始。
样例输入
[
[[255,0,0], [0,255,0],[0,0,255],[255,255, 0]],
[[0,255,255],[255,0,255],[255,255,255],[0,0,0]],
[[128,128,128],[64,64,64],[192,192,192],[32,32,32]],
[[16,16,16,[240,240,240],[80,80,80],[160,160,160]]
]
样例输出
[1,1,1,0]
[2,0,0,1]
[1,1,0,1]
[1,0,1,0]
样例1 | 输入是一个4行4列的RGB图像。通过PCA降维和K-Means聚类,像素点被分为3类(标签为0,1,2)。例如,第一行的所有像素被归为第1类,表示这些像素在降维后的特征空间中相似。 |
数据范围
- 图像大小不超过
- 像素值在
到
之间
- 图像通道数为
(RGB)
题解
这道题目要求我们实现一个图像处理流程,包括读取图像数据、降维和聚类。
首先,我们需要理解输入数据的结构:它是一个三维列表,代表一个彩色图像,形状为高度(H) × 宽度(W) × 通道数(C)。我们需要将其重组为一个二维矩阵,其中每一行代表一个像素,每一列代表一个特征(通道值)。
然后,我们使用PCA(主成分分析)将数据从C维降到2维。PCA是一种常用的降维技术,它通过寻找数据中的主要变化方向,保留最有信息量的特征,从而减少数据的维度。在scikit-learn中,我们可以使用PCA
类来实现这一步。
接着,我们对降维后的数据应用K-Means聚类算法。K-Means是一种常见的聚类方法,它将数据点分配到K个预定义的簇中,使得每个点属于与其欧氏距离最近的簇中心。在本题中,K设为3,表示我们要将像素分为3类。同样,我们可以使用scikit-learn中的KMeans
类来实现。
最后,我们将聚类结果重新整理为原始图像的形状(去掉通道维度),并按要求输出每个像素的类别标签。
需要注意的是,题目要求我们设置特定的随机种子和初始化参数,以确保结果的可重现性:random_state=42和n_init=1。
时间复杂度主要由PCA和K-Means的计算决定,对于大小为H×W的图像,PCA的复杂度为O((H×W)×C²),K-Means的复杂度约为O(K×(H×W)×I),其中I是迭代次数,K是类别数(此处为3)。考虑到题目的数据范围(最大100×100的图像),这个复杂度是可以接受的。
参考代码
- Python
import sys
import ast
import numpy as np
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
def solve():
# 读取输入数据
data = sys.stdin.read().strip()
# 解析为Python对象
imgs = ast.literal_eval(data)
# 获取图像尺寸
h = len(imgs)
w = len(imgs[0])
c = len(imgs[0][0])
# 将图像数据重组为样本矩阵
data = np.array(imgs).reshape(-1, c)
# 使用PCA降维到2维
pca = PCA(n_components=2, random_state=42)
low_dim = pca.fit_transform(data)
# 使用K-Means聚类
km = KMeans(n_clusters=3, random_state=42, n_init=1)
labels = km.fit_predict(low_dim)
# 将标签重塑为原始图像尺寸
result = labels.reshape(h, w)
# 输出结果
for row in result:
print(list(row))
if __name__ == "__main__":
solve()
- Cpp
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#include <sstream>
using namespace std;
// 简化版PCA实现
vector<vector<double>> pca(const vector<vector<double>>& data, int k, int seed) {
int n = data.size();
int d = data[0].size();
// 计算均值
vector<double> mean(d, 0);
for (int i = 0; i < n; i++) {
for (int j = 0; j < d; j++) {
mean[j] += data[i][j];
}
}
for (int j = 0; j < d; j++) {
mean[j] /= n;
}
// 中心化数据
vector<vector<double>> centered(n, vector<double>(d));
for (int i = 0; i < n; i++) {
for (int j = 0; j < d; j++) {
centered[i][j] = data[i][j] - mean[j];
}
}
// 计算协方差矩阵
vector<vector<double>> cov(d, vector<double>(d, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < d; j++) {
for (int k = 0; k < d; k++) {
cov[j][k] += centered[i][j] * centered[i][k];
}
}
}
for (int j = 0; j < d; j++) {
for (int k = 0; k < d; k++) {
cov[j][k] /= (n - 1);
}
}
// 此处简化处理,返回前k个特征方向的投影
// 实际应该计算特征值和特征向量
vector<vector<double>> projected(n, vector<double>(k));
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
projected[i][j] = centered[i][j];
}
}
return projected;
}
// 简化版K-Means实现
vector<int> kmeans(const vector<vector<double>>& data, int k, int seed) {
int n = data.size();
int d = data[0].size();
// 初始化聚类中心
srand(seed);
vector<vector<double>> centers(k, vector<double>(d));
for (int i = 0; i < k; i++) {
int idx = rand() % n;
centers[i] = data[idx];
}
vector<int> labels(n);
bool changed = true;
int iter = 0;
while (changed && iter < 100) {
changed = false;
// 分配标签
for (int i = 0; i < n; i++) {
double min_dist = 1e9;
int min_idx = 0;
for (int j = 0; j < k; j++) {
double dist = 0;
for (int dim = 0; dim < d; dim++) {
dist += pow(data[i][dim] - centers[j][dim], 2);
}
dist = sqrt(dist);
if (dist < min_dist) {
min_dist = dist;
min_idx = j;
}
}
if (labels[i] != min_idx) {
labels[i] = min_idx;
changed = true;
}
}
// 更新中心
vector<int> counts(k, 0);
vector<vector<double>> new_centers(k, vector<double>(d, 0));
for (int i = 0; i < n; i++) {
int label = labels[i];
counts[label]++;
for (int dim = 0; dim < d; dim++) {
new_centers[label][dim] += data[i][dim];
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力