【笔试刷题】阿里系列-2026.04.08-算法岗-改编真题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线200+套真题改编解析,后续会持续更新的
春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗
阿里系列-2026.04.08-算法岗
本场为阿里系共享机试,淘天、阿里云等方向均可参考,共 3 道编程题。整套题的结构比较分明:第一题是直角判定,考察基础几何与距离处理;第二题是典型的结构化计数,需要先识别合法子序列对应的是哪一段连续 1;第三题虽然题意像重排贪心,但核心模型其实是最小权完美匹配。
题目一:小基 的网格直角信标
关键在于把 3 个亮格直接视作平面上的 3 个点。题目里说的是“单元格中心”,但整体平移不会改变两点距离,所以直接用网格坐标计算三条边的平方距离,再套勾股关系判断即可。
难度:简单
题目二:小兰的亮灯片段子序列
这题的突破口是先把原串里所有 1 的位置抽出来。题目要求被选中的 1 在子序列里连续出现,且原串中相邻被选 1 之间不能再夹着别的 1,所以合法方案一定对应原串中一段连续的 1 位置块。块内 0 不能选,块外 0 都能自由取舍,答案自然转成幂次计数。
难度:中等
题目三:小柯的排座余数代价
这题最容易误入“排序 + 贪心”方向,但真正稳定的建模方式是把每个数和每个位置之间的代价写成 a_j mod i,然后做二分图最小权完美匹配。因为 n 很小,直接上 Hungarian 算法就足够。
难度:中等偏高
1. 小基 的网格直角信标
问题描述
说明:阿里系列近期多条业务线笔试题基本共用同一套公开机试,淘天、阿里云等方向都可参考本场。
小基 正在检查一块 的测试网格。网格中的每个单元格要么关闭,要么点亮,且整张网格里恰好只有
个单元格被点亮。
她把这 个点亮单元格的中心当作平面上的
个点,并把它们顺次连起来。现在她想知道,这
个点构成的三角形是不是直角三角形。
如果是直角三角形,输出 YES;否则输出 NO。
输入格式
每个测试文件包含多组测试数据。
- 第一行输入一个整数
,表示测试数据组数。
- 对于每组测试数据:
- 第一行输入一个整数
,表示网格边长。
- 接下来输入
行,每行是一个长度为
的 01 字符串。
- 第一行输入一个整数
保证每组数据中恰好有 个字符为
1。
输出格式
对于每组测试数据,输出一行一个字符串。
- 如果对应三角形是直角三角形,输出
YES。 - 否则输出
NO。
样例输入
2
3
001
000
101
3
001
010
100
样例输出
YES
NO
数据范围
- 单个测试文件中,所有测试数据的
之和不超过
| 样例 | 解释说明 |
|---|---|
| 样例 1 第 1 组 | 三个点分别在 YES。 |
| 样例 1 第 2 组 | 三个点共线,不会形成直角三角形,因此答案是 NO。 |
题解
先把三个点找出来
因为整张图里恰好只有 个
1,所以直接扫完整个网格,把这 个位置记下来即可。
虽然题目说的是“单元格中心”,但每个点都只是统一平移了 ,两两之间的距离不会变。所以直接把格子下标当作平面坐标来算就行。
用平方距离判断直角
设三点分别是 ,那么只需要算出:
把这三个值从小到大排序成 。
若三角形是直角三角形,那么一定满足勾股关系:
同时 不能为
,否则说明有两个点重合,但这题里本身不会出现这种情况。
复杂度分析
每组数据只需要扫一遍网格,再做常数次计算。
- 时间复杂度:
- 空间复杂度:
(不计输入存储,仅保存
个点)
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def dist2(a, b):
dx = a[0] - b[0]
dy = a[1] - b[1]
return dx * dx + dy * dy
def solve():
t = int(input())
out = []
for _ in range(t):
n = int(input())
pts = []
for i in range(n):
row = input()
for j, ch in enumerate(row):
if ch == "1":
pts.append((i, j))
d = [
dist2(pts[0], pts[1]),
dist2(pts[0], pts[2]),
dist2(pts[1], pts[2]),
]
d.sort()
out.append("YES" if d[0] > 0 and d[0] + d[1] == d[2] else "NO")
sys.stdout.write("\n".join(out))
if __name__ == "__main__":
solve()
- Cpp
#include <bits/stdc++.h>
using namespace std;
static int dist2(const pair<int, int>& a, const pair<int, int>& b) {
int dx = a.first - b.first;
int dy = a.second - b.second;
return dx * dx + dy * dy;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<pair<int, int>> pts;
for (int i = 0; i < n; ++i) {
string s;
cin >> s;
for (int j = 0; j < n; ++j) {
if (s[j] == '1') {
pts.push_back({i, j});
}
}
}
vector<int> d = {
dist2(pts[0], pts[1]),
dist2(pts[0], pts[2]),
dist2(pts[1], pts[2]),
};
sort(d.begin(), d.end());
cout << (d[0] > 0 && d[0] + d[1] == d[2] ? "YES" : "NO") << '\n';
}
return 0;
}
- Java
import java.io.BufferedInputStream;
import java.io.IOException;
public class Main {
static class FastScanner {
private final BufferedInputStream in = new BufferedInputStream(System.in);
private final byte[] buffer = new byte[1 << 16];
private int len = 0;
private int ptr = 0;
private int read() throws IOException {
if (ptr >= len) {
len = in.read(buffer);
ptr = 0;
if (len <= 0) {
return -1;
}
}
return buffer[ptr++];
}
String next() throws IOException {
int c;
do {
c = read();
} while (c <= ' ' && c != -1);
StringBuilder sb = new StringBuilder();
while (c > ' ') {
sb.append((char) c);
c = read();
}
return sb.toString();
}
int nextInt() throws IOException {
return Integer.parseInt(next());
}
}
static int dist2(int x1, int y1, int x2, int y2) {
int dx = x1 - x2;
int dy = y1 - y2;
return dx * dx + dy * dy;
}
public static void main(String[] args) throws Exception {
FastScanner fs = new FastScanner();
StringBuilder out = new StringBuilder();
int T = fs.nextInt();
while (T-- > 0) {
int n = fs.nextInt();
int[] xs = new int[3];
int[] ys = new int[3];
int cnt = 0;
for (int i = 0; i < n; ++i) {
String s = fs.next();
for (int j = 0; j < n; ++j) {
if (s.charAt(j) == '1') {
xs[cnt] = i;
ys[cnt] = j;
cnt++;
}
}
}
int[] d = new int[3];
d[0] = dist2(xs[0], ys[0], xs[1], ys[1]);
d[1] = dist2(xs[0], ys[0], xs[2], ys[2]);
d[2] = dist2(xs[1], ys[1], xs[2], ys[2]);
java.util.Arrays.sort(d);
out.append(d[0] > 0 && d[0] + d[1] == d[2] ? "YES" : "NO").append('\n');
}
System.out.print(out);
}
}
2. 小兰的亮灯片段子序列
问题描述
说明:阿里系列近期多条业务线笔试题基本共用同一套公开机试,淘天、阿里云等方向都可参考本场。
小兰 手里有一个长度为 的 01 串
。她想从中删去若干字符,保留相对顺序不变,得到一个新的子序列。
她只关心满足下面三个条件的子序列数量:
- 子序列里恰好有
个
1; - 这
个
1在子序列中必须连续出现; - 对于子序列中任意相邻的两个
1,它们在原串里之间不能夹着其他1。
请你计算满足要求的子序列个数。答案对 取模。
这里的“子序列”指的是:从原串中删除任意个字符(可以一个都不删),剩余字符保持相对顺序不变后得到的新串。
输入格式
每个测试文件包含多组测试数据。
- 第一行输入一个整数
,表示测试数据组数。
- 对于每组测试数据:
- 第一行输入两个整数
。
- 第二行输入一个长度为
的 01 字符串
。
- 第一行输入两个整数
输出格式
对于每组测试数据,输出一行一个整数,表示满足条件的子序列数量。
样例输入
3
5 2
01101
4 1
0010
6 3
101101
样例输出
6
8
4
数据范围
仅由
0和1组成- 单个测试文件中,所有测试数据的
之和不超过
| 样例 | 解释说明 |
|---|---|
| 样例 1 第 1 组 | 取连续的两颗 1 有两种方式:选位置 0 可自由取舍,贡献 0 可选,贡献 |
| 样例 1 第 2 组 | 只存在一个 1,而 1 必选,其余三个 0 都可以自由保留或删除,答案是 |
题解
先只关心原串里所有 1 的位置
设原串中 1 的位置依次是:
如果一个合法子序列里选中了若干个 1,由于题目要求“任意相邻的两个 1 中间不能再有别的 1”,那么这些被选中的 1 一定对应着原串里的一段连续位置块:
并且这段块的长度必须恰好是 。
所以,合法方案只可能来自“从所有 1 里选出一段连续的 个”。
选定这段 1 之后,哪些 0 还能自由选
假设当前选择的是:
那么:
- 这段内部的
1必须全部选中; - 这些
1之间夹着的0不能被选,否则子序列中的1就不会连续; - 段外的
0都可以随便选或不选,因为它们只会出现在整段1的左边或右边。
因此,答案贡献只和“段外一共有多少个 0”有关。
计算一段连续 1 的贡献
设当前块的左端是第 个
1,右端是第 个
1。
块左边可自由选择的 0 数量是:
因为在位置 之前一共有
个字符,其中恰好有
个是
1。
同理,块右边可自由选择的 0 数量是:
于是总贡献就是:
把所有长度为 的连续
1 块都枚举一遍求和即可。
复杂度分析
先扫一遍字符串找出所有 1 的位置,再枚举每个长度为 的连续块。
- 时间复杂度:
- 空间复杂度:
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
MOD = 998244353
def solve():
t = int(input())
out = []
for _ in range(t):
n, m = map(int, input().split())
s = input()
pos = [i + 1 for i, ch in enumerate(s) if ch == "1"]
k = len(pos)
if k < m:
out.append("0")
continue
pow2 = [1] * (n + 1)
for i in range(1, n + 1):
pow2[i] = (pow2[i - 1] * 2) % MOD
ans = 0
for l in range(k - m + 1):
r = l + m - 1
left_zero = pos[l] - (l + 1)
right_zero = (n - pos[r]) - (k - (r + 1))
ans += pow2[left_zero + right_zero]
if ans >= MOD:
ans -= MOD
out.append(str(ans))
sys.stdout.write("\n".join(out))
if __name__ == "__main__":
solve()
- Cpp
#include <bits/stdc++.h>
using namespace std;
static const int MOD = 998244353;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n, m;
string s;
cin >> n >> m >> s;
vector<in
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力