🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员
✨ 本系列打算持续跟新小米近期的春秋招笔试题汇总~
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
📧 清隆这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 清隆领取,会在飞书进行同步的跟新。
文章目录
- 🧷 01.获取公共链表片段
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 🔗 02.矿车运输成本
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 📎 03.最优索引选择
- 题目描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 写在最后
- 📧 清隆这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 清隆领取,会在飞书进行同步的跟新。
🧷 01.获取公共链表片段
问题描述
给定两个链表,找出它们中相同节点值的最大连续片段。如果没有公共片段,返回 -1。
输入格式
第一行表示链表 1,第二行表示链表 2。每条链表长度不超过 20 个元素,链表不会为空。
输出格式
输出两个链表中相同节点值的最大连续片段。如果没有公共片段,返回 -1。
样例输入
1 2 2 3 9 1 5
9 2 2 3 6 8
样例输出
2 2 3
数据范围
链表长度不超过 20 个元素。
题解
本题数据范围比较小,怎么做都可以,使用双重循环遍历两个链表,并在找到相同节点时,继续向后比较,直到不相同为止。记录最长的公共片段并输出。
参考代码
- Python
a, b = list(map(int, input().split())), list(map(int, input().split()))
n, m = len(a), len(b)
max_len = 0
res = []
for i in range(n):
for j in range(m):
if a[i] == b[j]:
z = i
for k in range(j, m):
if b[k] != a[z]:
break
z += 1
if z - i > max_len:
max_len = z - i
res = a[i:z]
print(*res if res else -1)
- Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<Integer> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();
while (sc.hasNextInt()) {
a.add(sc.nextInt());
}
sc.nextLine();
while (sc.hasNextInt()) {
b.add(sc.nextInt());
}
int n = a.size();
int m = b.size();
int maxLen = 0;
List<Integer> res = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a.get(i).equals(b.get(j))) {
int z = i;
int k = j;
while (k < m && z < n && a.get(z).equals(b.get(k))) {
z++;
k++;
}
if (z - i > maxLen) {
maxLen = z - i;
res = a.subList(i, z);
}
}
}
}
if (res.isEmpty()) {
System.out.println(-1);
} else {
for (int num : res) {
System.out.print(num + " ");
}
}
}
}
- Cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> a, b;
int num;
while (cin >> num) {
a.push_back(num);
if (cin.get() == '\n') break;
}
while (cin >> num) {
b.push_back(num);
if (cin.get() == '\n') break;
}
int n = a.size(), m = b.size();
int max_len = 0;
vector<int> res;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (a[i] == b[j]) {
int z = i;
int k = j;
while (k < m && z < n && a[z] == b[k]) {
++z;
++k;
}
if (z - i > max_len) {
max_len = z - i;
res.assign(a.begin() + i, a.begin() + z);
}
}
}
}
if (res.empty()) {
cout << -1 << endl;
} else {
for (int num : res) {
cout << num << " ";
}
}
return 0;
}
🔗 02.矿车运输成本
问题描述
露天矿采矿作业的特点是规模大,矿石和废料的移动量达到百万吨,运输成本开销较大,需要寻求一种最优的运输路径节省成本。
已知矿场可以划分成 N × M N \times M N×M 的网格图,每个网格存在地形的差异,因此通过不同网格时,成本开销存在差异。
网格有以下 5 种类型:
- 标志为 ‘S’ 的网格为运输起点;
- 标志为 ‘E’ 的网格为运输终点;
- 标志为 ‘B’ 的网格为阻塞点,不允许通行;
- 标志为 ‘C’ 的网格为检查点,矿车在运输路径中,至少需要进入一次检查点;
- 标志为数字的网格,其数字表示经过该网格的成本开销。
运输矿车只能上下左右 4 个方向运行,不允许斜对角进入其他网格。必要时可重复进入网格。请根据输入的网格图,寻求一条从 ‘S’ 网格到 ‘E’ 网格,并且至少经过一次检查点的最低成本运输路径,并输出其成本开销。
输入格式
第一行包含两个正整数 N N N 和 M M M,表示网格图的行数和列数,使用空格隔开。
接下来的 N N N 行,每行包含 M M M 个元素,元素可以为 ‘S’,‘E’,‘B’,‘C’ 或者数字 [0, 100],并且有且仅有一个 ‘S’ 和一个 ‘E’,同时存在一个或者多个 ‘C’,并依次使用空格隔开。
输出格式
输出运输最低成本开销。如果不存在可达通路,请输出 -1。
样例输入
3 3
S 4 5
7 B 3
C 9 E
样例输出
16
数据范围
- 3 ≤ N ≤ 200 3 \leq N \leq 200 3≤N≤200
- 3 ≤ M ≤ 200 3 \leq M \leq 200 3≤M≤200
题解
为了找到从起点 ‘S’ 到终点 ‘E’ 并且至少经过一次检查点 ‘C’ 的最低成本路径,可以跑两次 dijkstra。首先从起点 ‘S’ 到每个检查点 ‘C’ 计算最短路径,然后从每个检查点 ‘C’ 到终点 ‘E’ 计算最短路径,最后取所有路径中成本最小的路径即可。
参考代码
- Python
import heapq
def bfs(grid, start, end, n, m):
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
pq = [(0, start[0], start[1])]
dist = [[float('inf')] * m for _ in range(n)]
dist[start[0]][start[1]] = 0
while pq:
d, x, y = heapq.heappop(pq)
if (x, y) == end:
return d
if d > dist[x][y]:
continue
for i in range(4):
nx, ny = x + dx[i], y + dy[i]
if 0 <= nx < n and 0 <= ny < m and grid[nx][ny] != 'B':
cost = 0 if grid[nx][ny] in 'SEC' else int(grid[nx][ny])
if dist[nx][ny] > dist[x][y] + cost:
dist[nx][ny] = dist[x][y] + cost
heapq.heappush(pq, (dist[nx][ny], nx, ny))
return float('inf')
def main():
n, m = map(int, input().split())
grid = [input().split() for _ in range(n)]
start, end, checkpoints = None, None, []
for i in range(n):
for j in range(m):
if grid[i][j] == 'S':
start = (i, j)
elif grid[i][j] == 'E':
end = (i, j)
elif grid[i][j] == 'C':
checkpoints.append((i, j))
min_cost = float('inf')
for checkpoint in checkpoints:
cost = bfs(grid, start, checkpoint, n, m) + bfs(grid, checkpoint, end, n, m)
min_cost = min(min_cost, cost)
print(min_cost if min_cost != float('inf') else -1)
if __name__ == "__main__":
main()
- Java
import java.util.*;
public class Main {
static int[] dx = {-1, 0, 1, 0};
static int[] dy = {0, 1, 0, -1};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
sc.nextLine();
String[][] grid = new String[n][m];
int[] start = new int[2];
int[] end = new int[2];
List<int[]> checkpoints = new ArrayList<>();
for (int i = 0; i < n; i++) {
grid[i] = sc.nextLine().split(" ");
for (int j = 0; j < m; j++) {
if (grid[i][j].equals("S")) {
start[0] = i;
start[1] = j;
} else if (grid[i][j].equals("E")) {
end[0] = i;
end[1] = j;
} else if (grid[i][j].equals("C")) {
checkpoints.add(new int[]{i, j});
}
}
}
int minCost = Integer.MAX_VALUE;
for (int[] checkpoint : checkpoints) {
int cost = bfs(grid, start, checkpoint, n, m) + bfs(grid, checkpoint, end, n, m);
minCost = Math.min(minCost, cost);
}
System.out.println(minCost == Integer.MAX_VALUE ? -1 : minCost);
}
private static int bfs(String[][] grid, int[] start, int[] end, int n, int m) {
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
pq.add(new int[]{0, start[0], start[1]});
int[][] dist = new int[n][m];
for (int[] row : dist) Arrays.fill(row, Integer.MAX_VALUE);
dist[start[0]][start[1]] = 0;
while (!pq.isEmpty()) {
int[] curr = pq.poll();
int d = curr[0], x = curr[1], y = curr[2];
if (x == end[0] && y == end[1]) return d;
if (d > dist[x][y]) continue;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && !grid[nx][ny].equals("B")) {
int cost = grid[nx][ny].matches("\\d") ? Integer.parseInt(grid[nx][ny]) : 0;
if (dist[nx][ny] > dist[x][y] + cost) {
dist[nx][ny] = dist[x][y] + cost;
pq.add(new int[]{dist[nx][ny], nx, ny});
}
}
}
}
return Integer.MAX_VALUE;
}
}
- Cpp
#include <iostream>
#include <vector>
#include <queue>
#include <array>
#include <string>
#include <limits>
using namespace std;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
int bfs(const vector<vector<string>>& grid, pair<int, int> start, pair<int, int> end, int n, int m) {
priority_queue<array<int, 3>, vector<array<int, 3>>, greater<array<int, 3>>> pq;
pq.push({0, start.first, start.second});
vector<vector<int>> dist(n, vector<int>(m, numeric_limits<int>::max()));
dist[start.first][start.second] = 0;
while (!pq.empty()) {
auto [d, x, y] = pq.top();
pq.pop();
if (make_pair(x, y) == end) return d;
if (d > dist[x][y]) continue;
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] != "B") {
int cost = (grid[nx][ny] != "S" && grid[nx][ny] != "E" && grid[nx][ny] != "C") ? stoi(grid[nx][ny]) : 0;
if (dist[nx][ny] > dist[x][y] + cost) {
dist[nx][ny] = dist[x][y] + cost;
pq.push({dist[nx][ny], nx, ny});
}
}
}
}
return numeric_limits<int>::max();
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<string>> grid(n, vector<string>(m));
pair<int, int> start, end;
vector<pair<int, int>> checkpoints;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> grid[i][j];
if (grid[i][j] == "S") start = {i, j};
else if (grid[i][j] == "E") end = {i, j};
else if (grid[i][j] == "C") checkpoints.push_back({i, j});
}
}
int minCost = numeric_limits<int>::max();
for (const auto& checkpoint : checkpoints) {
int cost = bfs(grid, start, checkpoint, n, m) + bfs(grid, checkpoint, end, n, m);
minCost = min(minCost, cost);
}
cout << (minCost == numeric_limits<int>::max() ? -1 : minCost) << endl;
return 0;
}
📎 03.最优索引选择
题目描述
K小姐是一名数据库管理员,最近她接到了一个新的任务。公司的数据库系统有 N N N 个表,每个表都可以建立索引以提高查询效率,但建立索引也会占用一定的存储空间。通过对业务查询的分析,K小姐得到了每个表建立索引的查询效率提升值和存储空间开销。
为了方便管理,K小姐将所有的索引分成了 M M M 组,并且这些索引组之间存在一定的依赖关系和互斥关系:
- 依赖关系:如果要选择一个索引组中的索引,必须先选择它的父索引组中的至少一个索引。
- 互斥关系:每条从根节点到叶子节点的路径都代表一个互斥关系,即不能同时选择两个不同路径上的索引。
- 组内限制:对于每个索引组,必须至少选择其中的一个索引。
K小姐希望在总存储空间开销不超过 B B B 的情况下,选择一些索引使得总的查询效率提升值最大。你能帮助K小姐完成这个任务吗?
输入格式
第一行包含三个正整数 B B B, N N N, M M M,分别表示总存储空间开销上限、表的数量和索引组的数量。
接下来 N N N 行,每行包含三个正整数 G i G_i Gi, V i V_i Vi, C i C_i Ci,分别表示第 i i i 个表的索引所属的组号、查询效率提升值和存储空间开销。
最后一行包含 M M M 个整数,第 i i i 个整数 F i F_i Fi 表示第 i i i 个索引组的父索引组编号。如果 F i = − 1 F_i=-1 Fi=−1,则表示第 i i i 个索引组没有父索引组,即它是根索引组。
输出格式
输出一个整数,表示在满足总存储空间开销上限的情况下,可以获得的最大查询效率提升值。
样例输入
40 4 2
0 10 10
1 30 10
0 5 20
1 60 40
-1 0
样例输出
45
数据范围
- 1 ≤ B ≤ 5000 1 \le B \le 5000 1≤B≤5000
- 1 ≤ N ≤ 10000 1 \le N \le 10000 1≤N≤10000
- 1 ≤ M ≤ 100 1 \le M \le 100 1≤M≤100
- 0 ≤ G i < M 0 \le G_i < M 0≤Gi<M
- 1 ≤ V i , C i ≤ 100 1 \le V_i,C_i \le 100 1≤Vi,Ci≤100
题解
本题可以使用树形DP来解决。设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示以第 i i i 个索引组为根,总存储空间开销不超过 j j j 的情况下,可以获得的最大查询效率提升值。
对于每个索引组,我们首先需要在组内至少选择一个索引。我们可以使用01背包的方法,计算出在组内选择任意个索引的最优解,存储在数组 f [ j ] f[j] f[j] 中。
然后,我们再考虑当前索引组的子索引组。对于每个子索引组,我们可以枚举当前索引组选择的存储空间开销 j ′ j' j′,然后将子索引组的最优解 d p [ s o n ] [ j − j ′ ] dp[son][j-j'] dp[son][j−j′] 加到 f [ j ′ ] f[j'] f[j′] 上。这样,我们就可以得到以当前索引组为根,考虑了子索引组的最优解。
最后,根索引组的 d p [ r o o t ] [ B ] dp[root][B] dp[root][B] 就是整个问题的最优解。
时间复杂度 O ( B × N ) O(B \times N) O(B×N),空间复杂度 O ( B × M ) O(B \times M) O(B×M)。
参考代码
- Python
B, N, M = map(int, input().split())
indexes = [[] for _ in range(M)]
for _ in range(N):
g, v, c = map(int, input().split())
indexes[g].append((v, c))
father = list(map(int, input().split()))
graph = [[] for _ in range(M)]
root = 0
for i in range(M):
if father[i] == -1:
root = i
else:
graph[father[i]].append(i)
dp = [[0] * (B + 1) for _ in range(M)]
def dfs(u, limit):
f = [0] * (limit + 1)
for v, c in indexes[u]:
for j in range(limit, c - 1, -1):
f[j] = max(f[j], f[j - c] + v)
dp[u][limit] = f[limit]
for son in graph[u]:
cur = 0
for j in range(limit):
dfs(son, limit - j)
if f[j] != 0:
cur = max(cur, f[j] + dp[son][limit - j])
dp[u][limit] = max(dp[u][limit], cur)
dfs(root, B)
print(dp[root][B])
- Java
import java.io.*;
import java.util.*;
public class Main {
int B, N, M;
int[][] indexes;
int[] father;
List<Integer>[] graph;
int[][] dp;
public static void main(String[] args) throws IOException {
new Main().run();
}
void run() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] ss = br.readLine().split(" ");
B = Integer.parseInt(ss[0]);
N = Integer.parseInt(ss[1]);
M = Integer.parseInt(ss[2]);
indexes = new int[M][];
for (int i = 0; i < M; i++) {
indexes[i] = new int[0];
}
for (int i = 0; i < N; i++) {
ss = br.readLine().split(" ");
int g = Integer.parseInt(ss[0]);
int v = Integer.parseInt(ss[1]);
int c = Integer.parseInt(ss[2]);
indexes[g] = Arrays.copyOf(indexes[g], indexes[g].length + 2);
indexes[g][indexes[g].length - 2] = v;
indexes[g][indexes[g].length - 1] = c;
}
father = new int[M];
ss = br.readLine().split(" ");
for (int i = 0; i < M; i++) {
father[i] = Integer.parseInt(ss[i]);
}
graph = new List[M];
for (int i = 0; i < M; i++) {
graph[i] = new ArrayList<>();
}
int root = 0;
for (int i = 0; i < M; i++) {
if (father[i] == -1) {
root = i;
} else {
graph[father[i]].add(i);
}
}
dp = new int[M][B + 1];
dfs(root, B);
System.out.println(dp[root][B]);
}
void dfs(int u, int limit) {
int[] f = new int[limit + 1];
for (int i = 0; i < indexes[u].length; i += 2) {
int v = indexes[u][i];
int c = indexes[u][i + 1];
for (int j = limit; j >= c; j--) {
f[j] = Math.max(f[j], f[j - c] + v);
}
}
dp[u][limit] = f[limit];
for (int son : graph[u]) {
int cur = 0;
for (int j = 0; j < limit; j++) {
dfs(son, limit - j);
if (f[j] != 0) {
cur = Math.max(cur, f[j] + dp[son][limit - j]);
}
}
dp[u][limit] = Math.max(dp[u][limit], cur);
}
}
}
- Cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXB = 5000;
const int MAXM = 100;
int B, N, M;
vector<pair<int, int>> indexes[MAXM];
vector<int> graph[MAXM];
int father[MAXM];
int dp[MAXM][MAXB + 1];
void dfs(int u, int limit) {
vector<int> f(limit + 1);
for (auto& p : indexes[u]) {
int v = p.first, c = p.second;
for (int j = limit; j >= c; j--) {
f[j] = max(f[j], f[j - c] + v);
}
}
dp[u][limit] = f[limit];
for (int son : graph[u]) {
int cur = 0;
for (int j = 0; j < limit; j++) {
dfs(son, limit - j);
if (f[j] != 0) {
cur = max(cur, f[j] + dp[son][limit - j]);
}
}
dp[u][limit] = max(dp[u][limit], cur);
}
}
int main() {
cin >> B >> N >> M;
for (int i = 0; i < N; i++) {
int g, v, c;
cin >> g >> v >> c;
indexes[g].emplace_back(v, c);
}
int root = 0;
for (int i = 0; i < M; i++) {
cin >> father[i];
if (father[i] == -1) {
root = i;
} else {
graph[father[i]].push_back(i);
}
}
dfs(root, B);
cout << dp[root][B] << endl;
return 0;
}
写在最后
📧 清隆这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 清隆领取,会在飞书进行同步的跟新。