【携程笔试题汇总】2024-04-16-携程春招笔试题-三语言题解(CPP/Python/Java)

🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员

✨ 本系列打算持续跟新携程近期的春秋招笔试题汇总~

💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导

👏 感谢大家的订阅➕ 和 喜欢💗

📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取,会在飞书进行同步的跟新,5月1日之前限时免费提供ing~

🛎 01.字符串修改

题目描述

LYA 正在学习英语单词,她想要在一个由小写字母组成的字符串中添加一些字符,使得修改后的字符串包含尽可能多的单词 “you”。每次添加操作只能在字符串的任意位置添加一个字符 ‘0’。LYA 想知道最少需要添加几次字符,才能使修改后的字符串包含最多的单词 “you”。

输入格式

输入一个仅由小写字母组成的字符串 s s s,字符串的长度不超过 2 × 1 0 5 2 \times 10^5 2×105

输出格式

输出一个整数,表示最少需要添加的字符数量。

样例输入

yuyouy

样例输出

1

数据范围

  • 1 ≤ ∣ s ∣ ≤ 2 × 1 0 5 1 \leq |s| \leq 2 \times 10^5 1s2×105
  • 字符串 s s s 仅由小写字母组成

题解

这道题可以通过贪心的思想来解决。我们可以遍历字符串,统计相邻的字符 ‘y’ 和 ‘u’ 的个数,即统计子串 “yu” 的出现次数。最少需要添加的字符数量就等于子串 “yu” 的出现次数。

具体步骤如下:

  1. 初始化结果变量 r e s res res 0 0 0,表示最少需要添加的字符数量。
  2. 遍历字符串 s s s,对于每个位置 i i i
    • 如果当前字符 s [ i ] s[i] s[i] 为 ‘u’,且前一个字符 s [ i − 1 ] s[i-1] s[i1] 为 ‘y’,则将 r e s res res 的值加 1 1 1
  3. 遍历结束后,输出 r e s res res 的值作为最少需要添加的字符数量。

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1),其中 n n n 为字符串的长度。

参考代码

  • Python
s = input()
n = len(s)
res = 0
for i in range(1, n):
    if s[i] == 'u' and s[i - 1] == 'y':
        res += 1
print(res)
  • Java
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int n = s.length();
        int res = 0;
        for (int i = 1; i < n; i++) {
            if (s.charAt(i) == 'u' && s.charAt(i - 1) == 'y') {
                res++;
            }
        }
        System.out.println(res);
    }
}
  • Cpp
#include <iostream>
#include <string>

using namespace std;

int main() {
    string s;
    cin >> s;
    int n = s.length();
    int res = 0;
    for (int i = 1; i < n; i++) {
        if (s[i] == 'u' && s[i - 1] == 'y') {
            res++;
        }
    }
    cout << res << endl;
    return 0;
}

🛍 02.K小姐的礼物分配问题

问题描述

K小姐准备给她的三个好朋友A先生、B先生和C先生送礼物。她准备了三份礼物,分别装在三个盒子里,盒子的大小分别用正整数 a i a_i ai, b i b_i bi, c i c_i ci 表示。

为了公平起见,K小姐希望尽可能多的盒子满足条件: a i + b i = c i a_i+b_i=c_i ai+bi=ci,即某个盒子的大小恰好等于另外两个盒子大小的和。现在K小姐想知道,在不改变 a a a b b b 盒子大小的情况下,最多有多少个盒子能满足上述条件?

输入格式

第一行包含一个正整数 n n n,表示每份礼物盒子的数量。

第二行包含 n n n 个正整数 a 1 , a 2 , ⋯   , a n a_1, a_2, \cdots, a_n a1,a2,,an,表示第一份礼物中每个盒子的大小。

第三行包含 n n n 个正整数 b 1 , b 2 , ⋯   , b n b_1, b_2, \cdots, b_n b1,b2,,bn,表示第二份礼物中每个盒子的大小。

第四行包含 n n n 个正整数 c 1 , c 2 , ⋯   , c n c_1, c_2, \cdots, c_n c1,c2,,cn,表示第三份礼物中每个盒子的大小。

输出格式

输出一个整数,表示最多有多少个盒子满足条件 a i + b i = c i a_i+b_i=c_i ai+bi=ci

样例输入

4
1 2 3 4
2 3 4 5
4 5 6 7

样例输出

2

数据范围

  • 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105
  • 1 ≤ a i , b i , c i ≤ 2 × 1 0 9 1 \leq a_i, b_i, c_i \leq 2 \times 10^9 1ai,bi,ci2×109

题解

可以用哈希表来解决这个问题。具体步骤如下:

  • 用一个哈希表 d d d 统计数组 a a a b b b 中每一对元素的和出现的次数。

  • 用另一个哈希表 c c c 统计数组 c c c 中每个元素出现的次数。

  • 遍历哈希表 d d d,对于每个键值对 ( k , v ) (k, v) (k,v),如果 k k k 也在哈希表 c c c 中出现,则说明有 min ⁡ ( v , c [ k ] ) \min(v, c[k]) min(v,c[k]) 个盒子满足条件 a i + b i = c i a_i+b_i=c_i ai+bi=ci,将这个值累加到答案中。

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)

参考代码

  • Python
import sys
from collections import Counter

def solve():
    n = int(sys.stdin.readline())
    a = list(map(int, sys.stdin.readline().split()))
    b = list(map(int, sys.stdin.readline().split()))
    c_cnt = Counter(map(int, sys.stdin.readline().split()))
    
    ab_sum_cnt = Counter()
    for x, y in zip(a, b):
        ab_sum_cnt[x + y] += 1
    
    res = 0
    for s, cnt in ab_sum_cnt.items():
        res += min(cnt, c_cnt[s])
    
    print(res)

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));
        int n = Integer.parseInt(br.readLine());
        int[] a = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        int[] b = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        int[] c = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        
        Map<Integer, Integer> abSumCnt = new HashMap<>();
        for (int i = 0; i < n; i++) {
            int sum = a[i] + b[i];
            abSumCnt.put(sum, abSumCnt.getOrDefault(sum, 0) + 1);
        }
        
        Map<Integer, Integer> cCnt = new HashMap<>();
        for (int x : c) {
            cCnt.put(x, cCnt.getOrDefault(x, 0) + 1);
        }
        
        int res = 0;
        for (Map.Entry<Integer, Integer> entry : abSumCnt.entrySet()) {
            int sum = entry.getKey(), cnt = entry.getValue();
            if (cCnt.containsKey(sum)) {
                res += Math.min(cnt, cCnt.get(sum));
            }
        }
        
        System.out.println(res);
    }
}
  • Cpp
#include <iostream>
#include <unordered_map>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    int a[n], b[n], c[n];
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < n; i++) cin >> b[i];
    for (int i = 0; i < n; i++) cin >> c[i];
    
    unordered_map<int, int> abSumCnt;
    for (int i = 0; i < n; i++) {
        abSumCnt[a[i] + b[i]]++;
    }
    
    unordered_map<int, int> cCnt;
    for (int i = 0; i < n; i++) {
        cCnt[c[i]]++;
    }
    
    int res = 0;
    for (auto& p : abSumCnt) {
        int sum = p.first, cnt = p.second;
        if (cCnt.count(sum)) {
            res += min(cnt, cCnt[sum]);
        }
    }
    
    cout << res << endl;
    return 0;
}

🪞 03.老K的生日宴会

老K是一位非常有名的数学家,他的朋友遍布全球。一年一度的生日宴会上,来自世界各地的朋友们都会带来一份礼物,其中有些礼物的价值对数学家老K来说更有研究价值。

在宴会上,大家玩起了一个有趣的游戏:每次可以选择相邻的两件礼物,如果这两件礼物都是质数,就可以将它们合并成一件新的礼物,价值等于两件礼物的价值之和。合并后原来的两件礼物就从礼物列表中删除了,由新的礼物代替。

老K希望通过合并,使得最终剩下的礼物数量尽可能少。作为老K的好朋友,你能帮助他计算出最少能剩下多少件礼物吗?

输入格式

第一行包含一个正整数 n n n,表示初始时的礼物数量。

第二行包含 n n n 个正整数,表示从左到右每件礼物的价值。

输出格式

输出一个整数,表示合并后最少的礼物数量。

样例输入

5
1 3 2 5 4

样例输出

3

数据范围

1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105
1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10^6 1ai106

题解

本题的关键是要考虑合并的顺序。

首先,除了 2 2 2 以外的质数都是奇数,奇数与奇数相加一定是偶数,不可能再与其他数合并。而 2 2 2 与一个质数相加,有可能还是质数,有可能继续合并。所以我们要优先考虑 2 2 2 的合并。

遍历礼物列表,如果遇到 2 2 2,就看看左右两边的数是否为质数,如果是质数并且与 2 2 2 相加还是质数,就进行合并。

除了 2 2 2 之外,其余质数只需要与相邻的质数合并即可。

我们可以用一个变量 c n t cnt cnt 记录当前连续的质数个数,遇到偶数就将 c n t cnt cnt 清零,遇到奇数质数就将 c n t cnt cnt 1 1 1。每遇到一个偶数,就将之前的连续质数个数除以 2 2 2 加到答案中,然后 c n t cnt cnt 清零。

最后再将剩余的 c n t cnt cnt 除以 2 2 2 加到答案中即可。

参考代码

  • Python
import math

def is_prime(x):
    if x < 2:
        return False
    for i in range(2, int(math.sqrt(x)) + 1):
        if x % i == 0:
            return False
    return True

n = int(input())
a = list(map(int, input().split()))

ans = 0
cnt = 0
for i in range(n):
    if a[i] == 2:
        if i > 0 and is_prime(a[i-1]) and is_prime(a[i]+a[i-1]):
            cnt += 2
        elif i < n-1 and is_prime(a[i+1]) and is_prime(a[i]+a[i+1]):
            cnt += 2
    elif is_prime(a[i]):
        cnt += 1
    else:
        ans += cnt // 2
        cnt = 0

ans += cnt // 2
print(n - ans)
  • Java
import java.io.*;
import java.util.*;

public class Main {
    static boolean isPrime(int x) {
        if (x < 2) return false;
        for (int i = 2; i * i <= x; i++) {
            if (x % i == 0) return false;
        }
        return true;
    }

    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();
        }
        
        int ans = 0, cnt = 0;
        for (int i = 0; i < n; i++) {
            if (a[i] == 2) {
                if (i > 0 && isPrime(a[i-1]) && isPrime(a[i]+a[i-1])) {
                    cnt += 2;
                } else if (i < n-1 && isPrime(a[i+1]) && isPrime(a[i]+a[i+1])) {
                    cnt += 2;
                }
            } else if (isPrime(a[i])) {
                cnt++;
            } else {
                ans += cnt / 2;
                cnt = 0;
            }
        }
        ans += cnt / 2;
        System.out.println(n - ans);
    }
}
  • Cpp
#include <iostream>
using namespace std;

bool isPrime(int x) {
    if (x < 2) return false;
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0) return false;
    }
    return true;
}

int main() {
    int n;
    cin >> n;
    int a[n];
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    
    int ans = 0, cnt = 0;
    for (int i = 0; i < n; i++) {
        if (a[i] == 2) {
            if (i > 0 && isPrime(a[i-1]) && isPrime(a[i]+a[i-1])) {
                cnt += 2;
            } else if (i < n-1 && isPrime(a[i+1]) && isPrime(a[i]+a[i+1])) {
                cnt += 2;
            }
        } else if (isPrime(a[i])) {
            cnt++;
        } else {
            ans += cnt / 2;
            cnt = 0; 
        }
    }
    ans += cnt / 2;
    cout << n - ans << endl;
    
    return 0;
}

💊 04.卢小姐的树园直径测算

问题描述

卢小姐是一位热爱自然的园艺师,她在自己的园子里种植了一种非常特殊的树,这些树的生长模式形成了一个巨大的树形网络。在一个悠闲的午后,卢小姐想要测量这个网络的直径。在这里,我们定义树的直径为树中任意两个节点之间距离的最大值。为了更好地了解这个网络,卢小姐决定在每个节点上尝试种植一个新的树苗,并观察这对树的直径的影响。

我们用 f ( i ) f(i) f(i) 来表示在第 i i i 个节点上添加一个新的树苗后,树的直径的长度。卢小姐希望你能帮她计算出从 f ( 1 ) f(1) f(1) f ( n ) f(n) f(n) 的所有值。

输入格式

第一行包含一个正整数 n n n,代表树的节点数量。

接下来的 n − 1 n - 1 n1 行,每行包含两个正整数 u , v u, v u,v,代表节点 u u u 和节点 v v v 之间有一条长度为 1 1 1 的边连接。

输出格式

输出共 n n n 行,第 i i i 行包含一个整数,代表 f ( i ) f(i) f(i) 的值。

样例输入

5
1 2
2 3
3 4
2 5

样例输出

4
3
3
4
4

数据范围

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1u,vn

题解

在这个问题中,我们首先需要找到树的直径。为此,我们可以选择任意一个节点作为起点,进行一次深度优先搜索(DFS),找到距离它最远的节点。然后,以这个最远的节点为起点,再进行一次 DFS,找到距离它最远的节点,这两个节点之间的距离即为树的直径。

当我们在某个节点上添加一个新的树苗时,树的直径可能会增加,也可能保持不变。如果这个节点在原有直径的路径上,那么直径不会改变;如果不在,那么直径可能会增加。因此,我们需要计算每个节点到原直径两端的距离,取这些距离中的最大值加 1 1 1,与原直径长度比较,取最大值即为 f ( i ) f(i) f(i)

参考代码

  • Python
import sys

sys.setrecursionlimit(10**7)

def calculate_diameter():
    n = int(input())
    paths = [[] for _ in range(n + 1)]
    for _ in range(n - 1):
        u, v = map(int, input().split())
        paths[u].append(v)
        paths[v].append(u)

    def dfs(node, parent, distance):
        for neighbor in paths[node]:
            if neighbor == parent:
                continue
            distance[neighbor] = distance[node] + 1
            dfs(neighbor, node, distance)

    distance_from_root = [0] * (n + 1)
    distance_from_first_end = [0] * (n + 1)
    distance_from_second_end = [0] * (n + 1)

    dfs(1, 0, distance_from_root)
    first_end, _ = max(enumerate(distance_from_root), key=lambda x: x[1])

    dfs(first_end, 0, distance_from_first_end)
    second_end, diameter_length = max(enumerate(distance_from_first_end), key=lambda x: x[1])

    dfs(second_end, 0, distance_from_second_end)

    for i in range(1, n + 1):
        f_i = max(diameter_length, distance_from_second_end[i] + 1, distance_from_first_end[i] + 1)
        print(f_i)

calculate_diameter()
  • Java
import java.util.*;

public class TreeDiameter {
    static List<List<Integer>> paths;
    static int[] distanceFromRoot, distanceFromFirstEnd, distanceFromSecondEnd;
    static int n;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        paths = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            paths.add(new ArrayList<>());
        }
        for (int i = 1; i < n; i++) {
            int u = sc.nextInt();
            int v = sc.nextInt();
            paths.get(u).add(v);
            paths.get(v).add(u);
        }
        distanceFromRoot = new int[n + 1];
        distanceFromFirstEnd = new int[n + 1];
        distanceFromSecondEnd = new int[n + 1];
        calculateDiameter();
    }

    static void dfs(int node, int parent, int[] distance) {
        for (int neighbor : paths.get(node)) {
            if (neighbor != parent) {
                distance[neighbor] = distance[node] + 1;
                dfs(neighbor, node, distance);
            }
        }
    }

    static void calculateDiameter() {
        dfs(1, 0, distanceFromRoot);
        int firstEnd = 0, maxDistance = 0;
        for (int i = 1; i <= n; i++) {
            if (distanceFromRoot[i] > maxDistance) {
                maxDistance = distanceFromRoot[i];
                firstEnd = i;
            }
        }
        dfs(firstEnd, 0, distanceFromFirstEnd);
        int secondEnd = 0;
        maxDistance = 0;
        for (int i = 1; i <= n; i++) {
            if (distanceFromFirstEnd[i] > maxDistance) {
                maxDistance = distanceFromFirstEnd[i];
                secondEnd = i;
            }
        }
        int diameterLength = maxDistance;
        dfs(secondEnd, 0, distanceFromSecondEnd);
        for (int i = 1; i <= n; i++) {
            int f_i = Math.max(diameterLength, Math.max(distanceFromSecondEnd[i] + 1, distanceFromFirstEnd[i] + 1));
            System.out.println(f_i);
        }
    }
}
  • Cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 100010;
vector<int> paths[MAXN];
int distanceFromRoot[MAXN], distanceFromFirstEnd[MAXN], distanceFromSecondEnd[MAXN];
int n;

void dfs(int node, int parent, int distance[]) {
    for (int neighbor : paths[node]) {
        if (neighbor != parent) {
            distance[neighbor] = distance[node] + 1;
            dfs(neighbor, node, distance);
        }
    }
}

void calculateDiameter() {
    dfs(1, 0, distanceFromRoot);
    pair<int, int> firstEnd = {0, 0};
    for (int i = 1; i <= n; ++i) {
        if (distanceFromRoot[i] > firstEnd.second) {
            firstEnd = {i, distanceFromRoot[i]};
        }
    }
    dfs(firstEnd.first, 0, distanceFromFirstEnd);
    pair<int, int> secondEnd = {0, 0};
    for (int i = 1; i <= n; ++i) {
        if (distanceFromFirstEnd[i] > secondEnd.second) {
            secondEnd = {i, distanceFromFirstEnd[i]};
        }
    }
    int diameterLength = secondEnd.second;
    dfs(secondEnd.first, 0, distanceFromSecondEnd);
    for (int i = 1; i <= n; ++i) {
        int f_i = max(diameterLength, max(distanceFromSecondEnd[i] + 1, distanceFromFirstEnd[i] + 1));
        cout << f_i << endl;
    }
}

int main() {
    cin >> n;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        paths[u].push_back(v);
        paths[v].push_back(u);
    }
    calculateDiameter();
    return 0;
}

写在最后

📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取,会在飞书进行同步的跟新,5月1日之前限时免费提供ing~

在这里插入图片描述

在这里插入图片描述

  • 21
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023年3月11日,美团春季招聘笔试中共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符串处理的问题。需要使用字符串的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值