🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员
✨ 本系列打算持续跟新小米近期的春秋招笔试题汇总~
💻 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;
}
 
 
写在最后
📧 清隆这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 清隆领取,会在飞书进行同步的跟新。

 


















