🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员
✨ 本系列打算持续跟新蚂蚁近期的春秋招笔试题汇总~
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取,会在飞书进行同步的跟新。
文章目录
🧸 01.购物优惠
题目描述
K小姐来到了一家超市购物,超市里有 n n n 种商品,每种商品只能购买一件。其中有些商品支持优惠活动,如果用支付宝付款可以享受 95 95 95 折优惠,有些商品则不支持优惠。K小姐的支付宝余额为 m m m 元,她想知道最多能买几件商品。
输入格式
第一行包含两个正整数 n n n 和 m m m,分别表示商品的种类数和支付宝余额。
第二行包含 n n n 个正整数,表示每种商品的价格。
第三行包含一个长度为 n n n 的字符串,仅由 0 0 0 和 1 1 1 组成。若第 i i i 个字符为 1 1 1,则表示第 i i i 种商品支持优惠;否则表示不支持优惠。
输出格式
输出一个整数,表示最多能购买的商品数量。
样例输入
3 975
1000 500 500
0 0 1
样例输出
2
数据范围
- 1 ≤ n ≤ 100 1 \leq n \leq 100 1≤n≤100
- 1 ≤ m ≤ 1 0 5 1 \leq m \leq 10^5 1≤m≤105
- 商品价格均为正整数,且不超过 1 0 4 10^4 104。
题解
可以先将所有商品的价格乘以相应的折扣(支持优惠的乘以 0.95 0.95 0.95,不支持的乘以 1 1 1),然后将商品按照价格从小到大排序。接下来,从价格最小的商品开始,依次购买,直到无法再购买为止。最后购买的商品数量即为答案。
具体步骤如下:
- 读入 n n n, m m m 以及 n n n 个商品的价格和优惠信息。
- 根据优惠信息,将支持优惠的商品价格乘以 0.95 0.95 0.95。
- 将所有商品按照价格从小到大排序。
- 初始化答案 a n s = 0 ans = 0 ans=0,当前花费 s u m = 0 sum = 0 sum=0。
- 从价格最小的商品开始,依次尝试购买:
- 如果当前花费加上该商品的价格不超过 m m m,则购买该商品,将答案 a n s ans ans 加 1 1 1,当前花费 s u m sum sum 加上该商品价格。
- 否则,无法再购买,退出循环。
- 输出答案 a n s ans ans。
时间复杂度 O ( n log n ) O(n \log n) O(nlogn),空间复杂度 O ( n ) O(n) O(n)。
参考代码
- Python
n, m = map(int, input().split())
prices = list(map(int, input().split()))
discounts = input()
for i in range(n):
if discounts[i] == '1':
prices[i] *= 0.95
prices.sort()
ans = total = 0
for price in prices:
total += price
if total <= m:
ans += 1
else:
break
print(ans)
- Java
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
double[] prices = new double[n];
for (int i = 0; i < n; i++) {
prices[i] = sc.nextDouble();
}
String discounts = sc.next();
for (int i = 0; i < n; i++) {
if (discounts.charAt(i) == '1') {
prices[i] *= 0.95;
}
}
Arrays.sort(prices);
int ans = 0;
double total = 0;
for (double price : prices) {
total += price;
if (total <= m) {
ans++;
} else {
break;
}
}
System.out.println(ans);
}
}
- Cpp
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
double prices[n];
for (int i = 0; i < n; i++) {
cin >> prices[i];
}
string discounts;
cin >> discounts;
for (int i = 0; i < n; i++) {
if (discounts[i] == '1') {
prices[i] *= 0.95;
}
}
sort(prices, prices + n);
int ans = 0;
double total = 0;
for (double price : prices) {
total += price;
if (total <= m) {
ans++;
} else {
break;
}
}
cout << ans << endl;
return 0;
}
🎁 02.字母识别
题目描述
LYA 正在开发一个字母识别系统。现在她得到了一些由 '.'
和 '*'
组成的矩阵图案,希望你帮忙识别图案中 '*'
字符表示的是字母 'L'
还是 'T'
。注意,图案可能会被旋转或翻转。
输入格式
第一行输入一个正整数 T T T,表示询问的组数。
对于每组询问:
- 第一行输入两个正整数 n n n 和 m m m,分别表示图案矩阵的行数和列数。
- 接下来
n
n
n 行,每行输入一个长度为
m
m
m 的、仅包含
'.'
和'*'
的字符串,表示图案矩阵。
保证字母宽度为 1 1 1,且每一笔都是水平或垂直的。
输出格式
输出
T
T
T 行,对于每组询问,如果答案是 'L'
则输出 "L"
,如果是 'T'
则输出 "T"
。
样例输入
2
4 4
....
..*.
..*.
***.
5 6
..*...
..*...
..*...
******
......
样例输出
L
T
数据范围
- 1 ≤ T ≤ 100 1 \leq T \leq 100 1≤T≤100
- 1 ≤ n , m ≤ 100 1 \leq n, m \leq 100 1≤n,m≤100
题解
本题可以通过观察字母 'L'
和 'T'
的特点来判断。
对于字母 'L'
,每个 '*'
格子最多与其他两个 '*'
格子相邻。而对于字母 'T'
,必定存在一个 '*'
格子与其他三个 '*'
格子相邻。
因此,可以遍历矩阵中的每个 '*'
格子,统计其相邻的 '*'
格子数量。如果存在一个格子相邻的 '*'
格子数量大于等于
3
3
3,则说明这是一个 'T'
,否则就是 'L'
。
具体步骤如下:
- 读入询问组数 T T T。
- 对于每组询问:
- 读入矩阵的行数 n n n 和列数 m m m,以及 n n n 行矩阵。
- 初始化标记变量 f l a g flag flag 为 f a l s e false false。
- 遍历矩阵中的每个格子
(
i
,
j
)
(i, j)
(i,j):
- 如果当前格子为
'*'
,则统计其上下左右四个相邻格子中'*'
的数量 c n t cnt cnt。 - 如果 c n t ≥ 3 cnt \geq 3 cnt≥3,则将 f l a g flag flag 置为 t r u e true true。
- 如果当前格子为
- 如果
f
l
a
g
flag
flag 为
t
r
u
e
true
true,则输出
"T"
,否则输出"L"
。
时间复杂度 O ( T × n × m ) O(T \times n \times m) O(T×n×m),空间复杂度 O ( n × m ) O(n \times m) O(n×m)。
参考代码
- Python
T = int(input())
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
for _ in range(T):
n, m = map(int, input().split())
grid = [input() for _ in range(n)]
flag = False
for i in range(n):
for j in range(m):
if grid[i][j] == '*':
cnt = sum(1 for k in range(4) if 0 <= i + dx[k] < n and 0 <= j + dy[k] < m and grid[i + dx[k]][j + dy[k]] == '*')
if cnt >= 3:
flag = True
print("T" if flag else "L")
- Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
while (T-- > 0) {
int n = sc.nextInt();
int m = sc.nextInt();
char[][] grid = new char[n][m];
for (int i = 0; i < n; i++) {
grid[i] = sc.next().toCharArray();
}
boolean flag = false;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == '*') {
int cnt = 0;
for (int k = 0; k < 4; k++) {
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == '*') {
cnt++;
}
}
if (cnt >= 3) {
flag = true;
}
}
}
}
System.out.println(flag ? "T" : "L");
}
}
}
- Cpp
#include <iostream>
using namespace std;
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};
int main() {
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
char grid[n][m];
for (int i = 0; i < n; i++) {
cin >> grid[i];
}
bool flag = false;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == '*') {
int cnt = 0;
for (int k = 0; k < 4; k++) {
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == '*') {
cnt++;
}
}
if (cnt >= 3) {
flag = true;
}
}
}
}
cout << (flag ? "T" : "L") << endl;
}
return 0;
}
🎉 03.最大公约数之旅
问题描述
K小姐计划进行一次旅行。她有一个长度为 n n n 的整数数组,表示她每天的旅行预算。在旅行开始之前,她可以将这个数组按任意顺序重新排列。
接下来,K小姐需要将数组分成两个非空的部分,使得这两部分的元素和的最大公约数最大。她想知道这个最大的最大公约数是多少。
输入格式
第一行包含一个正整数 n n n,表示数组的长度。
第二行包含 n n n 个以空格分隔的正整数,表示数组中的元素。
输出格式
输出一个整数,表示两部分元素和的最大公约数的最大值。
样例输入
3
1 2 3
样例输出
3
数据范围
1
≤
n
≤
100
1 \leq n \leq 100
1≤n≤100
1
≤
a
i
≤
100
1 \leq a_i \leq 100
1≤ai≤100
题解
本题可以使用动态规划来解决。可以先求出数组元素的总和 s u m sum sum,然后定义一个布尔型数组 d p dp dp,其中 d p [ i ] dp[i] dp[i] 表示是否可以从数组中选出一些元素,使得它们的和等于 i i i。
初始时, d p = t r u e dp=true dp=true,因为可以不选任何元素。接下来,遍历数组中的每个元素 a a a,对于每个 j j j 从 s u m sum sum 到 a a a 递减,如果 d p [ j − a ] dp[j-a] dp[j−a] 为 t r u e true true,则将 d p [ j ] dp[j] dp[j] 更新为 t r u e true true。这样做的目的是,如果可以选出一些元素使得它们的和等于 j − a j-a j−a,那么再加上当前元素 a a a,就可以得到和为 j j j 的一种方案。
最后,遍历 d p dp dp 数组,对于每个为 t r u e true true 的 d p [ i ] dp[i] dp[i],将数组分成两部分,一部分的元素和为 i i i,另一部分的元素和为 s u m − i sum-i sum−i。我们计算这两部分元素和的最大公约数,并更新答案。
时间复杂度为 O ( n × s u m ) O(n \times sum) O(n×sum),空间复杂度为 O ( s u m ) O(sum) O(sum)。
参考代码
- Python
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
n = int(input())
arr = list(map(int, input().split()))
total = sum(arr)
dp = [False] * (total + 1)
dp[0] = True
for num in arr:
for j in range(total, num - 1, -1):
dp[j] |= dp[j - num]
ans = 0
for i in range(1, total):
if dp[i]:
left = i
right = total - i
if left and right:
ans = max(ans, gcd(left, right))
print(ans)
- Java
import java.util.Scanner;
public class Main {
public static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
int total = 0;
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
total += arr[i];
}
boolean[] dp = new boolean[total + 1];
dp[0] = true;
for (int num : arr) {
for (int j = total; j >= num; j--) {
dp[j] |= dp[j - num];
}
}
int ans = 0;
for (int i = 1; i < total; i++) {
if (dp[i]) {
int left = i;
int right = total - i;
if (left != 0 && right != 0) {
ans = Math.max(ans, gcd(left, right));
}
}
}
System.out.println(ans);
}
}
- Cpp
#include <iostream>
#include <vector>
using namespace std;
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int main() {
int n;
cin >> n;
vector<int> arr(n);
int total = 0;
for (int i = 0; i < n; i++) {
cin >> arr[i];
total += arr[i];
}
vector<bool> dp(total + 1, false);
dp[0] = true;
for (int num : arr) {
for (int j = total; j >= num; j--) {
dp[j] |= dp[j - num];
}
}
int ans = 0;
for (int i = 1; i < total; i++) {
if (dp[i]) {
int left = i;
int right = total - i;
if (left && right) {
ans = max(ans, gcd(left, right));
}
}
}
cout << ans << endl;
return 0;
}
写在最后
📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取,会在飞书进行同步的跟新。