🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员
✨ 本系计划跟新各公司春秋招的笔试题
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
📧 清隆这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注CSDN同名公主号领取,会在飞书进行同步的跟新。
文章目录
- 📖 写在前面
- 夏天要来了 秋招还会远吗?
- ✨ 01.K小姐的魔药配方
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- ⚡️ 02.K小姐的魔法阵
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 💽 03.K小姐的魔法咒语
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 🎀 写在最后
- 🛖 这里介绍一下咱们的笔试打卡小屋
- 🥰 打卡奖励
- 🕰 每日学习安排
- 📖 打卡小屋涉及题型
- 基础算法
- 基础数据结构
- 搜索
- 动态规划 & 贪心 & 数论
📖 写在前面
夏天要来了 秋招还会远吗?
前不久春招也算是圆满结束咯,大家有拿到心仪的 offer吗?
接下来互联网的秋招也快来啦,小伙伴们有开始准备了吗?
本次给大家带来24届秋招 阿里系 的笔试题目三语言解析(Java/Python/Cpp)
文末有清隆学长的笔试陪伴打卡小屋活动介绍:
✨丰富的打卡奖励等你来领哦,大厂笔试题汇总,笔试面试经验贴,算法笔试模版…
💽 有兴趣的小伙伴们也可以了解一下,不要错过啦~
✨ 01.K小姐的魔药配方
问题描述
K小姐是一位魔药大师,她有 n n n 种魔药材料。每种材料都包含一定比例的稀有元素和普通元素。第 i i i 种材料中,稀有元素的比例为 a i % a_i\% ai%,普通元素的比例为 b i % b_i\% bi%。
K小姐想要配制一种魔药,要求稀有元素的比例不低于 50 % 50\% 50%。她可以选择任意多种材料,将它们混合在一起。
请问,K小姐最多可以配制出多少份这样的魔药?
输入格式
第一行包含一个正整数 n n n( 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1≤n≤105),表示材料的种类数。
第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,…,an( 0 ≤ a i ≤ 100 0 \leq a_i \leq 100 0≤ai≤100),表示每种材料中稀有元素的比例。
第三行包含 n n n 个整数 b 1 , b 2 , … , b n b_1, b_2, \ldots, b_n b1,b2,…,bn( 0 ≤ b i ≤ 100 0 \leq b_i \leq 100 0≤bi≤100),表示每种材料中普通元素的比例。
保证对于每种材料,有 a i + b i = 100 a_i + b_i = 100 ai+bi=100。
输出格式
输出一个整数,表示K小姐最多可以配制出的魔药份数。
样例输入
3
50 60 30
50 40 70
样例输出
110
数据范围
- 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1≤n≤105
- 0 ≤ a i , b i ≤ 100 0 \leq a_i, b_i \leq 100 0≤ai,bi≤100
- a i + b i = 100 a_i + b_i = 100 ai+bi=100
题解
我们可以先将材料按照稀有元素的比例从高到低排序。然后从前往后选择材料,直到选择的材料中稀有元素的总比例不再大于等于 50 % 50\% 50%。
设前 i i i 种材料中,稀有元素的总比例为 s u m a sum_a suma,普通元素的总比例为 s u m b sum_b sumb。如果 s u m a ≥ s u m b sum_a \geq sum_b suma≥sumb,那么前 i i i 种材料就可以用来配制魔药。
我们可以用贪心的思想来证明这一做法的正确性。对于当前选择的材料,如果替换成任何一种未选择的材料,那么稀有元素的总比例一定会下降,因为未选择的材料的稀有元素比例一定小于等于当前材料。因此,我们的选择方案是最优的。
时间复杂度为 O ( n log n ) O(n \log n) O(nlogn),空间复杂度为 O ( n ) O(n) O(n)。
参考代码
- Python
n = int(input())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
materials = sorted(zip(a, b), reverse=True)
sum_a = sum_b = 0
ans = 0
for x, y in materials:
if sum_a + x >= sum_b + y:
sum_a += x
sum_b += y
ans += x
else:
break
print(ans)
- Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
for (int i = 0; i < n; i++) {
b[i] = sc.nextInt();
}
int[][] materials = new int[n][2];
for (int i = 0; i < n; i++) {
materials[i] = new int[]{a[i], b[i]};
}
Arrays.sort(materials, (x, y) -> y[0] - x[0]);
int sumA = 0, sumB = 0;
int ans = 0;
for (int[] m : materials) {
if (sumA + m[0] >= sumB + m[1]) {
sumA += m[0];
sumB += m[1];
ans += m[0];
} else {
break;
}
}
System.out.println(ans);
}
}
- Cpp
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n; i++) {
cin >> b[i];
}
vector<pair<int, int>> materials;
for (int i = 0; i < n; i++) {
materials.emplace_back(a[i], b[i]);
}
sort(materials.begin(), materials.end(), greater<pair<int, int>>());
int sumA = 0, sumB = 0;
int ans = 0;
for (auto& m : materials) {
if (sumA + m.first >= sumB + m.second) {
sumA += m.first;
sumB += m.second;
ans += m.first;
} else {
break;
}
}
cout << ans << endl;
return 0;
}
⚡️ 02.K小姐的魔法阵
问题描述
K小姐在探索一座神秘的魔法塔时,发现了一个奇特的魔法阵。这个魔法阵由 n n n 个魔法石组成,每个魔法石上都刻有一个正整数。然而,由于年代久远,魔法阵上的数字已经变得模糊不清。
K小姐凭借自己的魔法知识,了解到这个魔法阵的数字排列满足以下规律:如果将魔法石上的数字按顺序排列成一个序列 a a a,那么对于任意的 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,都有 a a i = n − i + 1 a_{a_i} = n - i + 1 aai=n−i+1。
现在,K小姐希望你能帮助她还原这个神秘的魔法阵。
输入格式
输入只包含一个正整数 n n n( 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1≤n≤105),表示魔法阵中魔法石的数量。
输出格式
如果能够还原出符合条件的魔法阵,则输出一行,包含 n n n 个正整数,表示还原后的魔法阵中每个魔法石上的数字。如果有多个可能的解,输出任意一个即可。
如果无法还原出符合条件的魔法阵,则输出一行,包含一个整数 − 1 -1 −1。
样例输入
5
样例输出
2 5 3 1 4
数据范围
- 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1≤n≤105
题解
我们可以根据给定的规律,直接构造出符合条件的魔法阵。
首先,我们可以发现,如果 n n n 为 4 4 4 的倍数或者 4 4 4 的倍数加 1 1 1,那么就一定存在符合条件的魔法阵。否则,无法构造出符合条件的魔法阵。
对于 n n n 为 4 4 4 的倍数或者 4 4 4 的倍数加 1 1 1 的情况,我们可以按照以下方式构造魔法阵:
- 对于 i i i 为奇数且 1 ≤ i ≤ n 2 1 \leq i \leq \frac{n}{2} 1≤i≤2n,令 a i = i + 1 a_i = i + 1 ai=i+1, a i + 1 = n − i + 1 a_{i+1} = n - i + 1 ai+1=n−i+1。
- 对于 i i i 为奇数且 1 ≤ i ≤ n 2 1 \leq i \leq \frac{n}{2} 1≤i≤2n,令 a n − i + 1 = n − i a_{n-i+1} = n - i an−i+1=n−i, a n − i = i a_{n-i} = i an−i=i。
- 如果 n n n 为奇数,令 a n + 1 2 = n + 1 2 a_{\frac{n+1}{2}} = \frac{n+1}{2} a2n+1=2n+1。
按照上述方式构造出的序列 a a a 即为符合条件的魔法阵。
时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)。
参考代码
- Python
n = int(input())
a = [0] * (n + 1)
if n % 4 == 0 or n % 4 == 1:
for i in range(1, n // 2 + 1, 2):
a[i] = i + 1
a[i + 1] = n - i + 1
a[n - i + 1] = n - i
a[n - i] = i
if n % 2 != 0:
a[n // 2 + 1] = n // 2 + 1
print(' '.join(map(str, a[1:])))
else:
print(-1)
- 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 + 1];
if (n % 4 == 0 || n % 4 == 1) {
for (int i = 1; i <= n / 2; i += 2) {
a[i] = i + 1;
a[i + 1] = n - i + 1;
a[n - i + 1] = n - i;
a[n - i] = i;
}
if (n % 2 != 0) {
a[n / 2 + 1] = n / 2 + 1;
}
for (int i = 1; i <= n; i++) {
System.out.print(a[i] + " ");
}
} else {
System.out.println(-1);
}
}
}
- Cpp
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int main() {
int n;
cin >> n;
if (n % 4 == 0 || n % 4 == 1) {
for (int i = 1; i <= n / 2; i += 2) {
a[i] = i + 1;
a[i + 1] = n - i + 1;
a[n - i + 1] = n - i;
a[n - i] = i;
}
if (n % 2 != 0) {
a[n / 2 + 1] = n / 2 + 1;
}
for (int i = 1; i <= n; i++) {
cout << a[i] << " ";
}
} else {
cout << -1 << endl;
}
return 0;
}
💽 03.K小姐的魔法咒语
问题描述
K小姐是一位强大的魔法师,她掌握了许多神奇的魔法咒语。这些咒语都是由小写字母组成的字符串。
在这些咒语中,有一类特殊的咒语,它们满足以下条件:在咒语中,有且仅有一种字母出现了偶数次,其余字母都出现了奇数次。
现在,K小姐想知道,给定一个字符串,它的子序列中有多少个是特殊咒语。注意,子序列可以不连续,但必须保持原有的相对顺序。
答案可能很大,请对 1 0 9 + 7 10^9+7 109+7 取模。
输入格式
输入一个由小写字母组成的字符串,长度不超过 2 × 1 0 5 2 \times 10^5 2×105。
输出格式
输出一个整数,表示特殊咒语的数量,答案需要对 1 0 9 + 7 10^9+7 109+7 取模。
样例输入
abccc
样例输出
12
数据范围
- 字符串长度不超过 2 × 1 0 5 2 \times 10^5 2×105。
题解
我们可以用组合数学的方法来解决这个问题。
对于每一种字母,我们统计它在字符串中出现的次数。如果某个字母出现了至少两次,那么我们可以选择其中的两个位置,组成一个特殊咒语的子序列。
设第 i i i 种字母出现了 c n t i cnt_i cnti 次,那么我们可以从中选择 2 2 2 个位置的方案数为 C ( c n t i , 2 ) C(cnt_i, 2) C(cnti,2)。
对于其他字母,我们可以选择是否将它们包含在子序列中。如果包含,就选择它们出现的所有位置;如果不包含,就一个位置也不选。因此,对于每种其他字母,我们有 2 c n t j 2^{cnt_j} 2cntj 种选择方案。
但是,我们需要排除掉同时选择两个位置的情况,因为那样就不是特殊咒语了。排除的方案数为 C ( c n t j , 2 ) C(cnt_j, 2) C(cntj,2)。
因此,对于每种出现至少两次的字母 i i i,它对答案的贡献为:
C ( c n t i , 2 ) × ∏ j ≠ i ( 2 c n t j − C ( c n t j , 2 ) ) C(cnt_i, 2) \times \prod_{j \neq i} (2^{cnt_j} - C(cnt_j, 2)) C(cnti,2)×j=i∏(2cntj−C(cntj,2))
我们将所有的贡献相加,就得到了最终的答案。
时间复杂度为 O ( n + 26 × 26 ) O(n + 26 \times 26) O(n+26×26),空间复杂度为 O ( n ) O(n) O(n)。其中 n n n 为字符串长度。
参考代码
- Python
mod = 10**9 + 7
c = [[0]*3 for _ in range(200010)]
sums = [0]*27
counts = [0]*27
def init():
for i in range(2, 200010):
c[i][2] = i * (i - 1) // 2 % mod
def get_res(x):
res = 1
for i in range(1, 27):
if x != i:
res = (res * sums[i]) % mod
return res
def qmi(a, b, mod):
res = 1
while b:
if b & 1:
res = (res * a) % mod
a = (a * a) % mod
b >>= 1
return res
if __name__ == "__main__":
s = input()
for i in s:
counts[ord(i) - ord('a') + 1] += 1
init()
for i in range(1, 27):
sums[i] = ((qmi(2, counts[i], mod)) % mod - c[counts[i]][2] + mod) % mod
res = 0
for i in range(1, 27):
if counts[i] >= 2:
res = (res + c[counts[i]][2] * get_res(i) % mod) % mod
print(res)
- Java
import java.util.Scanner;
public class Main {
static long[][] c = new long[200010][3];
static long[] sums = new long[27];
static long mod = (long) 1e9 + 7;
static long[] counts = new long[27];
static void init() {
for (int i = 2; i < 200010; i++) {
c[i][2] = (long) i * (i - 1) / 2 % mod;
}
}
static long getRes(int x) {
long res = 1;
for (int i = 1; i <= 26; i++) {
if (x != i) {
res = (res * sums[i]) % mod;
}
}
return res;
}
static long qmi(long a, long b, long mod) {
long res = 1;
while (b > 0) {
if ((b & 1) == 1) res = (res * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return res;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
for (int i = 0; i < s.length(); i++) {
counts[s.charAt(i) - 'a' + 1]++;
}
init();
for (int i = 1; i <= 26; i++) {
sums[i] = ((qmi(2, counts[i], mod)) % mod - c[(int) counts[i]][2] + mod) % mod;
}
long res = 0;
for (int i = 1; i <= 26; i++) {
if (counts[i] >= 2) {
res = (res + c[(int) counts[i]][2] * getRes(i) % mod) % mod;
}
}
System.out.println(res);
scanner.close();
}
}
- Cpp
#include <iostream>
using namespace std;
long long c[200010][3];
long long sums[27], mod = 1000000007, counts[27];
string s;
void init() {
for (int i = 2; i < 200010; i++) {
c[i][2] = ((long long)i * (i - 1) / 2) % mod;
}
}
long long getRes(int x) {
long long res = 1;
for (int i = 1; i <= 26; i++) {
if (x != i) {
res = (res * sums[i]) % mod;
}
}
return res;
}
long long qmi(long long a, long long b, long long mod) {
long long res = 1;
while (b) {
if (b & 1) res = (res * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return res;
}
int main() {
cin >> s;
for (int i = 0; i < s.size(); i++) {
counts[s[i] - 'a' + 1]++;
}
init();
for (int i = 1; i <= 26; i++) {
sums[i] = ((qmi(2, counts[i], mod)) % mod - c[counts[i]][2] + mod) % mod;
}
long long res = 0;
for (int i = 1; i <= 26; i++) {
if (counts[i] >= 2) {
res = (res + c[counts[i]][2] * getRes(i) % mod) % mod;
}
}
cout << res;
return 0;
}
🎀 写在最后
🛖 这里介绍一下咱们的笔试打卡小屋
✨ 打卡小屋旨在陪伴大家,养成每日学习的好习惯。在这里,你可以:
- 🤝 与备战笔试的小伙伴相识,找到志同道合的学习小组
- 📝 通过写题解,巩固做题思路,养成良好的记录习惯
- 💡 系统掌握常考算法和数据结构,了解互联网笔试难度
- 🎁 坚持打卡,获得丰厚奖励,激励自己持之以恒
🥰 打卡奖励
打卡时长 | 奖励内容 |
---|---|
7天 | 任选一家最新互联网笔试真题 x 1 (价值29.9r) |
14天 | 任选一家最新互联网笔试真题 x 3 + 笔试面试经验贴 |
21天 | 任选一家最新互联网笔试真题 x 5 + 清隆三语言算法模版 |
28天 | 最新互联网大厂笔试真题汇总(价值199r) + 华为OD机试训练营 (价值89r) |
7天打卡即可值回票价,心动不如行动!
🕰 每日学习安排
小屋将在每日上午发放打卡题目,包括:
- 一道算法模版题,帮助大家掌握常用算法套路
- 根据算法模版,精选一道对应的大厂笔试真题,巩固算法应用
让我们一起直击笔试重点,攻克常考题型!
📖 打卡小屋涉及题型
小屋从零基础出发,涵盖笔试常考知识点:
基础算法
- 自定义排序
- 二分
- 前缀和
- 差分
- 双指针
基础数据结构
- 栈 & 单调栈
- 队列 & 单调队列
- 并查集
- 优先队列(堆)
搜索
- DFS & BFS 基础应用
- 树的遍历
- 基础图论
动态规划 & 贪心 & 数论
- 快速幂
- 组合数
- 质数 & 因数
- 位运算
- 基础动态规划
- 常见贪心