介绍
豆包青训营是由字节跳动和稀土掘金社区共同发起的技术培训和人才选拔项目,主要面向在校大学生。该项目的目标是培养具有职业竞争力的优秀开发工程师,并提供全程免费的课程,不收取任何费用。
课程内容和方向
豆包青训营的课程涵盖前端、后端和AI方向。在这个飞速发展的AI时代,学员将与豆包MarsCode团队一起深入探索技术领域,学习和运用AI,提高编程效率。此外,课程还包括大数据方向,适合对大数据感兴趣的学员学习,
本文提供训练营试题解析供参考
试题1:我好想逃却逃不掉
问题描述:
def solution(N, M, data):
# 构建迷宫矩阵
maze = []
for row in data:
if isinstance(row, list):
maze.append(row)
else:
maze.append(list(row))
# 方向映射
directions = {
'U': (-1, 0), # 上
'D': (1, 0), # 下
'L': (0, -1), # 左
'R': (0, 1) # 右
}
def is_valid(x, y):
return 0 <= x < N and 0 <= y < M
def can_reach_exit(start_x, start_y, visited):
# 越界检查
if not is_valid(start_x, start_y):
return False
# 如果已经访问过,说明形成了环
if (start_x, start_y) in visited:
return False
# 到达出口
if maze[start_x][start_y] == 'O':
return True
# 记录当前位置为已访问
visited.add((start_x, start_y))
# 如果是传送点
if maze[start_x][start_y] in directions:
dx, dy = directions[maze[start_x][start_y]]
next_x, next_y = start_x + dx, start_y + dy
return can_reach_exit(next_x, next_y, visited)
# 如果是普通点,尝试四个方向
for dx, dy in directions.values():
next_x, next_y = start_x + dx, start_y + dy
if is_valid(next_x, next_y) and can_reach_exit(next_x, next_y, visited.copy()):
return True
return False
# 统计无法到达出口的位置数量
count = 0
for i in range(N):
for j in range(M):
if maze[i][j] != 'O': # 不考虑出口本身
if not can_reach_exit(i, j, set()):
count += 1
return count
if __name__ == "__main__":
# Add your test cases here
pattern = [
[".", ".", ".", ".", "."],
[".", "R", "R", "D", "."],
[".", "U", ".", "D", "R"],
[".", "U", "L", "L", "."],
[".", ".", ".", ".", "O"]
]
print(solution(5, 5, pattern) == 10)
试题2:小D的‘abc’变换问题
问题描述:
小D拿到了一个仅由 “abc” 三种字母组成的字符串。她每次操作会对所有字符同时进行以下变换:
将 ‘a’ 变成 ‘bc’
将 ‘b’ 变成 ‘ca’
将 ‘c’ 变成 ‘ab’
小D将重复该操作 k 次。你的任务是输出经过 k 次变换后,得到的最终字符串。
例如:对于初始字符串 “abc”,执行 2 次操作后,字符串将变为 “caababbcbcca”
def solution(s: str, k: int) -> str:
def transform(s: str) -> str:
# 初始化结果字符串
result = []
# 遍历输入字符串的每个字符
for char in s:
# 根据字符进行变换
if char == 'a':
result.append('bc')
elif char == 'b':
result.append('ca')
elif char == 'c':
result.append('ab')
# 将结果列表拼接成字符串
return ''.join(result)
# 初始化当前字符串为输入字符串
current_string = s
# 进行 k 次变换
for _ in range(k):
current_string = transform(current_string)
return current_string
if __name__ == '__main__':
print(solution("abc", 2) == 'caababbcbcca')
print(solution("abca", 3) == 'abbcbccabccacaabcaababbcabbcbcca')
print(solution("cba", 1) == 'abcabc')
试题3:组成字符串ku的最大次数
问题描述:
给定一个字符串 s,该字符串中只包含英文大小写字母。你需要计算从字符串中最多能组成多少个字符串 “ku”。每次可以随机从字符串中选一个字符,并且选中的字符不能再使用。字符串中的字符大小写可以忽略,即大写和小写字母视为相同。
例如,输入 “AUBTMKAxfuu”,从中最多能组成 1 个 “ku”。
public class Main {
public static int solution(String s) {
// 将字符串转换为小写,以便忽略大小写
s = s.toLowerCase();
// 初始化计数器
int kCount = 0;
int uCount = 0;
// 遍历字符串,统计 'k' 和 'u' 的出现次数
for (char c : s.toCharArray()) {
if (c == 'k') {
kCount++;
} else if (c == 'u') {
uCount++;
}
}
// 计算最多能组成的 "ku" 的数量
// 关键步骤:返回 kCount 和 uCount 中的较小值
return Math.min(kCount, uCount);
}
public static void main(String[] args) {
System.out.println(solution("AUBTMKAxfuu") == 1);
System.out.println(solution("KKuuUuUuKKKKkkkkKK") == 6);
System.out.println(solution("abcdefgh") == 0);
}
}
试题4:二分数字组合
问题描述:
小F面临一个有趣的挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。
例如,对于数组 [1, 1, 1] 和目标 A = 1,B = 2,可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。如果 A = 3,B = 5,当所有数字加和的个位数为 3 或 5 时,可以有一组为非空,另一组为空。
import java.util.ArrayList;
import java.util.List;
public class Main {
// 计算所有子序列的和
public static List<Integer> findAllSubsequenceSums(int[] array_a) {
List<Integer> sums = new ArrayList<>();
backtrack(array_a, 0, 0, 0, sums); // 添加一个参数表示当前子序列的大小
return sums;
}
// 回溯法生成所有子序列和
private static void backtrack(int[] array_a, int index, int currentSum, int size, List<Integer> sums) {
// 只在子序列非空时添加和
if (size > 0) {
sums.add(currentSum);
}
// 遍历每个元素,生成子序列
for (int i = index; i < array_a.length; i++) {
currentSum += array_a[i]; // 选择当前元素
backtrack(array_a, i + 1, currentSum, size + 1, sums); // 递归调用
currentSum -= array_a[i]; // 撤销选择
}
}
// 主要解决方案
public static int solution(int n, int A, int B, int[] array_a) {
int totalSum = 0;
for (int num : array_a) {
totalSum += num; // 计算总和
}
List<Integer> sums = findAllSubsequenceSums(array_a);
int count = 0;
// 遍历所有子序列和
for (int sum : sums) {
// 排除空子序列和整个原始序列的情况
if (sum % 10 == A && sum != totalSum) {
// 检查总和减去当前子序列和的个位数
if ((totalSum - sum) % 10 == B) {
count++; // 计数符合条件的分组
}
}
}
// 检查总和的个位数是否等于 A 或 B
if (totalSum % 10 == A || totalSum % 10 == B) {
count++; // 计数特殊情况
}
return count; // 返回结果
}
public static void main(String[] args) {
// 测试用例
int[] array1 = {1, 1, 1};
int[] array2 = {1, 1, 1};
int[] array3 = {1, 1};
// 输出验证
System.out.println(solution(3, 1, 2, array1) == 3);
System.out.println(solution(3, 3, 5, array2) == 1);
System.out.println(solution(2, 1, 1, array3) == 2);
}
}
试题5:卡牌翻面求和问题
问题描述:
def solution(n: int, a: list, b: list) -> int:
MOD = 10**9 + 7
# 初始化 dp 数组,dp[i] 表示当前和为 i 的组合数
dp = [0] * 3
dp[0] = 1
# 遍历每张卡牌
for i in range(n):
# 临时数组,用于存储更新后的 dp 值
new_dp = [0] * 3
# 对于当前卡牌的两个选择(正面或背面)
for j in range(3):
if dp[j] > 0:
# 选择正面
new_dp[(j + a[i]) % 3] = (new_dp[(j + a[i]) % 3] + dp[j]) % MOD
# 选择背面
new_dp[(j + b[i]) % 3] = (new_dp[(j + b[i]) % 3] + dp[j]) % MOD
# 更新 dp 数组
dp = new_dp
# 最终结果是 dp[0],即和为 0 的组合数
return dp[0]
if __name__ == '__main__':
print(solution(n = 3, a = [1, 2, 3], b = [2, 3, 2]) == 3)
print(solution(n = 4, a = [3, 1, 2, 4], b = [1, 2, 3, 1]) == 6)
print(solution(n = 5, a = [1, 2, 3, 4, 5], b = [1, 2, 3, 4, 5]) == 32)
试题6:游戏排名第三大的分数
问题描述:
小M想要通过查看往届游戏比赛的排名来确定自己比赛的目标分数。他希望找到往届比赛中排名第三的分数,作为自己的目标。具体规则如下:
1.如果分数中有三个或以上不同的分数,返回其中第三大的分数。
2.如果不同的分数只有两个或更少,那么小M将选择最大的分数作为他的目标。
请你帮小M根据给定的分数数组计算目标分数。
def solution(n: int, nums: list) -> int:
# 去重
unique_nums = list(set(nums))
# 降序排序
unique_nums.sort(reverse=True)
# 判断第三大的分数
if len(unique_nums) >= 3:
return unique_nums[2] # 返回第三大的分数
else:
return unique_nums[0] # 返回最大的分数
if __name__ == '__main__':
print(solution(3, [3, 2, 1]) == 1)
print(solution(2, [1, 2]) == 2)
print(solution(4, [2, 2, 3, 1]) == 1)