🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员
✨ 本系列打算持续跟新阿里近期的春秋招笔试题汇总~
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取,会在飞书进行同步的跟新。
文章目录
01.K小姐的魔法迷宫
题目描述
K小姐在一个 n × n n \times n n×n 的魔法迷宫中探险。迷宫的每个格子上都有一个魔法箭头,指示着走到该格子后应该前进的方向:
- ‘^’ 表示向上走
- ‘v’ 表示向下走
- ‘<’ 表示向左走
- ‘>’ 表示向右走
当 K小姐离开一个格子时,该格子上的箭头方向就会反转,即 ‘^’ 变成 ‘v’,‘v’ 变成 ‘^’,‘<’ 变成 ‘>’,‘>’ 变成 ‘<’。
给定 K小姐的初始位置,请问她需要走多少步才能走出迷宫?如果 K小姐永远无法走出迷宫,则输出 − 1 -1 −1。
输入格式
第一行输入一个整数 n n n,表示迷宫的大小。
接下来 n n n 行,每行输入一个长度为 n n n 的字符串,仅包含字符 ‘^’、‘v’、‘<’、‘>’,表示迷宫中每个格子的初始箭头方向。
最后一行输入两个整数 x x x 和 y y y,表示 K小姐的初始位置坐标。
输出格式
输出一个整数,表示 K小姐走出迷宫所需的步数。如果 K小姐永远无法走出迷宫,则输出 − 1 -1 −1。
样例输入
2
>v
^<
1 1
样例输出
5
数据范围
1
<
n
<
100
1 < n < 100
1<n<100
1
≤
x
,
y
≤
n
1 \le x, y \le n
1≤x,y≤n
题解
本题可以使用模拟的方法来解决。可以用一个二维数组来表示迷宫,每个格子的值表示箭头的方向。然后从 K小姐的初始位置开始,根据当前格子的箭头方向移动到下一个格子,同时将当前格子的箭头方向反转。重复这个过程,直到走出迷宫或者步数超过一个较大的值(表示无法走出迷宫)。
在实现时,可以用一个字符串 t
来存储四个方向的字符,并用一个二维数组 ne
来存储每个方向对应的坐标变化。这样可以方便地根据当前格子的箭头字符来计算下一步的坐标。
时间复杂度为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( n 2 ) O(n^2) O(n2)。
参考代码
- Python
n = int(input())
t = "^v><"
ne = [[-1, 0], [1, 0], [0, 1], [0, -1]]
maze = [list(map(t.find, input())) for _ in range(n)]
x, y = map(int, input().split())
x, y = x - 1, y - 1
step = 0
while step <= 10**6:
d = maze[x][y]
maze[x][y] ^= 1
x += ne[d][0]
y += ne[d][1]
step += 1
if x < 0 or x >= n or y < 0 or y >= n:
print(step)
exit()
print(-1)
- Java
import java.util.*;
public class Main {
static final int MAXN = 100;
static final int MAXSTEP = (int)1e6;
static final String DIRS = "^v><";
static final int[][] NEXT = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] maze = new int[MAXN][MAXN];
for (int i = 0; i < n; i++) {
String row = sc.next();
for (int j = 0; j < n; j++) {
maze[i][j] = DIRS.indexOf(row.charAt(j));
}
}
int x = sc.nextInt() - 1;
int y = sc.nextInt() - 1;
for (int step = 1; step <= MAXSTEP; step++) {
int d = maze[x][y];
maze[x][y] ^= 1;
x += NEXT[d][0];
y += NEXT[d][1];
if (x < 0 || x >= n || y < 0 || y >= n) {
System.out.println(step);
return;
}
}
System.out.println(-1);
}
}
- Cpp
#include <iostream>
#include <string>
using namespace std;
const int MAXN = 100;
const int MAXSTEP = 1e6;
const string DIRS = "^v><";
const int NEXT[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
int main() {
int n;
cin >> n;
int maze[MAXN][MAXN];
for (int i = 0; i < n; i++) {
string row;
cin >> row;
for (int j = 0; j < n; j++) {
maze[i][j] = DIRS.find(row[j]);
}
}
int x, y;
cin >> x >> y;
x--, y--;
for (int step = 1; step <= MAXSTEP; step++) {
int d = maze[x][y];
maze[x][y] ^= 1;
x += NEXT[d][0];
y += NEXT[d][1];
if (x < 0 || x >= n || y < 0 || y >= n) {
cout << step << endl;
return 0;
}
}
cout << -1 << endl;
return 0;
}
02.蛋糕大师
题目描述
K小姐是一位蛋糕制作高手,她计划制作 n n n 个蛋糕。每个蛋糕的制作都需要经过 m m m 个步骤,其中第 i i i 个步骤需要 a i a_i ai 个人同时参与,且需要持续 b i b_i bi 秒。
在每一秒,对于某个步骤,可以选择参与该步骤,或者跳过不参与。但是有以下限制:
- 对于一个蛋糕的制作,各个步骤必须按照顺序进行。即只有当前一个步骤完成后,才能开始下一个步骤。
- 在某一秒参与了某个蛋糕的某个步骤,就不能在这一秒参与其他任何步骤(包括同一个蛋糕的其他步骤)。
- 多个蛋糕的制作可以同时进行。
请问,最少需要多少秒,可以完成所有蛋糕的制作?
输入格式
第一行包含两个正整数 n n n 和 m m m,分别表示蛋糕数量和步骤数量。
接下来 m m m 行,每行包含两个正整数 a i a_i ai 和 b i b_i bi,表示第 i i i 个步骤需要的人数和持续时间。
输出格式
输出一个整数,表示最少需要的秒数。
样例输入
3 3
2 1
2 2
3 1
样例输出
6
数据范围
- 1 ≤ n , m ≤ 1000 1 \leq n,m \leq 1000 1≤n,m≤1000
- 1 ≤ a i ≤ 1000 1 \leq a_i \leq 1000 1≤ai≤1000
- 1 ≤ b i ≤ 1 0 9 1 \leq b_i \leq 10^9 1≤bi≤109
题解
本题可以用贪心 + 优先队列来解决。
首先,我们可以发现,对于每一个步骤,我们都应该尽可能早地开始制作,这样才能使总时间最短。
因此,我们可以用优先队列来维护每一个步骤的最早可开始时间。初始时,第一个步骤的最早可开始时间为 0 0 0,其他步骤的最早可开始时间为无穷大。
然后,我们从优先队列中取出当前时间最早的步骤,将其分配给尽可能多的蛋糕制作。分配完后,将下一个步骤的最早可开始时间更新,并加入优先队列。
重复上述过程,直到所有蛋糕都完成制作。最后的时间就是答案。
时间复杂度 O ( n m log m ) O(nm\log m) O(nmlogm),空间复杂度 O ( m ) O(m) O(m)。
参考代码
- Python
from heapq import heappush, heappop
def solve():
n, m = map(int, input().split())
step_people = []
step_time = []
for _ in range(m):
people, time = map(int, input().split())
step_people.append(people)
step_time.append(time)
events = []
capacity = [[[0, step_people[i]] for _ in range(1)] for i in range(m)]
first_batch = (n + step_people[0] - 1) // step_people[0]
current_time = 0
for _ in range(first_batch):
current_time += step_time[0]
heappush(events, (current_time, 1, step_people[0]))
completed = 0
while events:
current_time, current_step, required_people = heappop(events)
if current_step == m:
completed += required_people
if completed >= n:
print(current_time)
break
continue
for cap in capacity[current_step]:
if cap[0] <= current_time:
if required_people <= cap[1]:
cap[0] = current_time + step_time[current_step]
cap[1] = required_people
if cap[1] - required_people > 0:
capacity[current_step].append([cap[0], cap[1] - required_people])
heappush(events, (current_time + step_time[current_step], current_step + 1, required_people))
required_people = 0
break
else:
cap[0] = current_time + step_time[current_step]
heappush(events, (current_time + step_time[current_step], current_step + 1, cap[1]))
required_people -= cap[1]
if required_people > 0:
heappush(events, (capacity[current_step][0][0], current_step, required_people))
if __name__ == "__main__":
solve()
- 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));
String[] line = br.readLine().split(" ");
int n = Integer.parseInt(line[0]);
int m = Integer.parseInt(line[1]);
int[] stepPeople = new int[m];
int[] stepTime = new int[m];
for (int i = 0; i < m; i++) {
line = br.readLine().split(" ");
stepPeople[i] = Integer.parseInt(line[0]);
stepTime[i] = Integer.parseInt(line[1]);
}
PriorityQueue<long[]> events = new PriorityQueue<>((a, b) -> Long.compare(a[0], b[0]));
List<long[]>[] capacity = new List[m];
for (int i = 0; i < m; i++) {
capacity[i] = new ArrayList<>();
capacity[i].add(new long[]{0, stepPeople[i]});
}
int firstBatch = (n + stepPeople[0] - 1) / stepPeople[0];
long currentTime = 0;
for (int i = 0; i < firstBatch; i++) {
currentTime += stepTime[0];
events.offer(new long[]{currentTime, 1, stepPeople[0]});
}
int completed = 0;
while (!events.isEmpty()) {
long[] event = events.poll();
currentTime = event[0];
int currentStep = (int) event[1];
int requiredPeople = (int) event[2];
if (currentStep == m) {
completed += requiredPeople;
if (completed >= n) {
System.out.println(currentTime);
break;
}
continue;
}
for (long[] cap : capacity[currentStep]) {
if (cap[0] <= currentTime) {
if (requiredPeople <= cap[1]) {
cap[0] = currentTime + stepTime[currentStep];
cap[1] = requiredPeople;
if (cap[1] - requiredPeople > 0) {
capacity[currentStep].add(new long[]{cap[0], cap[1] - requiredPeople});
}
events.offer(new long[]{currentTime + stepTime[currentStep], currentStep + 1, requiredPeople});
requiredPeople = 0;
break;
} else {
cap[0] = currentTime + stepTime[currentStep];
events.offer(new long[]{currentTime + stepTime[currentStep], currentStep + 1, cap[1]});
requiredPeople -= cap[1];
}
}
}
if (requiredPeople > 0) {
events.offer(new long[]{capacity[currentStep].get(0)[0], currentStep, requiredPeople});
}
}
}
}
- Cpp
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
int main() {
int n, m;
cin >> n >> m;
vector<int> stepPeople(m);
vector<int> stepTime(m);
for (int i = 0; i < m; i++) {
cin >> stepPeople[i] >> stepTime[i];
}
priority_queue<vector<ll>, vector<vector<ll>>, greater<vector<ll>>> events;
vector<vector<vector<ll>>> capacity(m, vector<vector<ll>>(1, vector<ll>(2)));
for (int i = 0; i < m; i++) {
capacity[i][0][0] = 0;
capacity[i][0][1] = stepPeople[i];
}
int firstBatch = (n + stepPeople[0] - 1) / stepPeople[0];
ll currentTime = 0;
for (int i = 0; i < firstBatch; i++) {
currentTime += stepTime[0];
events.push({currentTime, 1, stepPeople[0]});
}
int completed = 0;
while (!events.empty()) {
auto event = events.top();
events.pop();
currentTime = event[0];
int currentStep = event[1];
int requiredPeople = event[2];
if (currentStep == m) {
completed += requiredPeople;
if (completed >= n) {
cout << currentTime << endl;
break;
}
continue;
}
for (auto& cap : capacity[currentStep]) {
if (cap[0] <= currentTime) {
if (requiredPeople <= cap[1]) {
cap[0] = currentTime + stepTime[currentStep];
cap[1] = requiredPeople;
if (cap[1] - requiredPeople > 0) {
capacity[currentStep].push_back({cap[0], cap[1] - requiredPeople});
}
events.push({currentTime + stepTime[currentStep], currentStep + 1, requiredPeople});
requiredPeople = 0;
break;
} else {
cap[0] = currentTime + stepTime[currentStep];
events.push({currentTime + stepTime[currentStep], currentStep + 1, cap[1]});
requiredPeople -= cap[1];
}
}
}
if (requiredPeople > 0) {
events.push({capacity[currentStep][0][0], currentStep, requiredPeople});
}
}
return 0;
}
03.K小姐的有向图探险
问题描述
K小姐是一位热衷于数学研究的女士。最近,她在研究一种特殊的有向图问题。
给定一个长度为 n n n 的排列 a 1 , a 2 , . . . , a n a_1, a_2, ..., a_n a1,a2,...,an,K小姐构建了一个有向图 G G G。图 G G G 中共有 n n n 个节点,节点编号从 1 1 1 到 n n n。对于每个 i i i (其中 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n),从节点 i i i 有一条有向边指向节点 a i a_i ai。
K小姐想知道在这个有向图 G G G 中,有多少个二元组 ⟨ p , q ⟩ \langle p, q \rangle ⟨p,q⟩ 满足从节点 p p p 出发可以到达节点 q q q。
输入格式
第一行包含一个正整数 n n n,表示排列的长度。
第二行包含 n n n 个用空格分隔的正整数 a 1 , a 2 , . . . , a n a_1, a_2, ..., a_n a1,a2,...,an,表示给定的排列。
输出格式
输出一个整数,表示满足条件的二元组 ⟨ p , q ⟩ \langle p, q \rangle ⟨p,q⟩ 的数量。
样例输入
3
1 3 2
样例输出
5
数据范围
- 2 ≤ n ≤ 1 0 5 2 \leq n \leq 10^5 2≤n≤105
- 1 ≤ a i ≤ n 1 \leq a_i \leq n 1≤ai≤n
题解
我们可以使用并查集的思想来解决这个问题。
首先,我们遍历排列 a a a,对于每个元素 a i a_i ai,我们从 i i i 出发,沿着有向边一直走下去,直到遇到一个已经访问过的节点或者形成了一个环。在这个过程中,我们将所有经过的节点都标记为已访问,并记录下这个环中节点的数量 c c c。
对于这个环中的任意两个节点 p p p 和 q q q,我们都可以从 p p p 到达 q q q,也可以从 q q q 到达 p p p。因此,对于这个环中的节点,我们可以构造 c 2 c^2 c2 个满足条件的二元组。
最后,我们将所有这些 c 2 c^2 c2 相加,就可以得到答案。
参考代码
- Python
n = int(input())
a = list(map(int, input().split()))
for i in range(n):
a[i] -= 1
vis = [0] * n
ans = 0
for i in range(n):
if vis[i]:
continue
vis[i] = 1
c = 1
j = a[i]
while j != i:
vis[j] = 1
j = a[j]
c += 1
ans += c * c
print(ans)
- Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt() - 1;
}
sc.close();
boolean[] vis = new boolean[n];
long ans = 0;
for (int i = 0; i < n; i++) {
if (vis[i]) {
continue;
}
vis[i] = true;
int c = 1;
int j = a[i];
while (j != i) {
vis[j] = true;
j = a[j];
c++;
}
ans += c * c * 1L;
}
System.out.println(ans);
}
}
- Cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
a[i]--;
}
vector<bool> vis(n, false);
long ans = 0;
for (int i = 0; i < n; i++) {
if (vis[i]) {
continue;
}
vis[i] = true;
int c = 1;
int j = a[i];
while (j != i) {
vis[j] = true;
j = a[j];
c++;
}
ans += 1ll * c * c;
}
cout << ans << endl;
return 0;
}
写在最后
📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取,会在飞书进行同步的跟新。