青训营-豆包MarsCode技术训练营试题解析九
介绍
豆包青训营是由字节跳动和稀土掘金社区共同发起的技术培训和人才选拔项目,主要面向在校大学生。该项目的目标是培养具有职业竞争力的优秀开发工程师,并提供全程免费的课程,不收取任何费用。
课程内容和方向
豆包青训营的课程涵盖前端、后端和AI方向。在这个飞速发展的AI时代,学员将与豆包MarsCode团队一起深入探索技术领域,学习和运用AI,提高编程效率。此外,课程还包括大数据方向,适合对大数据感兴趣的学员学习,
本文提供训练营试题解析供参考
试题1:最少字符串操作次数
问题描述:
小U得到一个只包含小写字母的字符串 S。她可以执行如下操作:每次选择字符串中两个相同的字符删除,然后在字符串末尾添加一个任意的小写字母。小U想知道,最少需要多少次操作才能使得字符串中的所有字母都不相同?
def solution(S: str) -> int:
# 统计每个字符出现的次数
from collections import Counter
char_count = Counter(S)
# 初始化操作次数
operations = 0
# 遍历字符计数,处理每个字符的出现次数
for count in char_count.values():
# 如果字符出现次数大于1,需要进行操作
if count > 1:
# 计算需要进行的操作次数
# 每次操作可以减少一对相同的字符
# 例如,如果有3个'a',需要2次操作(3 - 1)
operations += (count // 2)
return operations
if __name__ == '__main__':
print(solution(S = "abab") == 2) # True
print(solution(S = "aaaa") == 2) # True
print(solution(S = "abcabc") == 3) # True
试题2:石子移动问题
问题描述:
小S正在玩一个关于石子的游戏,给定了一些石子,它们位于一维数轴的不同位置,位置用数组 stones 表示。如果某个石子处于最小或最大的一个位置,我们称其为端点石子。
在每个回合,小S可以将一颗端点石子移动到一个未占用的位置,使其不再是端点石子。游戏继续,直到石子的位置变得连续,无法再进行任何移动操作。
你需要帮助小S找到可以移动的最大次数。
import java.util.Arrays;
public class Main {
public static int solution(int[] stones) {
if (stones.length == 1) {
return 0;
}
Arrays.sort(stones);
int n = stones.length;
// 计算最大移动次数
int maxMoves = Math.max(stones[n - 1] - stones[1], stones[n - 2] - stones[0]) - (n - 2);
// 计算最小移动次数,使用滑动窗口
int minMoves = Integer.MAX_VALUE;
int j = 0;
for (int i = 0; i < n; i++) {
// 确保窗口内最多有 n 个石子
while (j < n && stones[j] - stones[i] + 1 <= n) {
j++;
}
// 如果窗口内有 n - 1 个石子,且空位为 1,则需要特殊处理
int alreadyInPlace = j - i;
if (alreadyInPlace == n - 1 && stones[j - 1] - stones[i] + 1 == n - 1) {
minMoves = Math.min(minMoves, 2);
} else {
minMoves = Math.min(minMoves, n - alreadyInPlace);
}
}
return maxMoves;
}
public static void main(String[] args) {
System.out.println(solution(new int[]{7, 4, 9})); // 输出: 2
System.out.println(solution(new int[]{6, 5, 4, 3, 10})); // 输出: 3
System.out.println(solution(new int[]{1, 2, 3, 4, 5})); // 输出: 0
}
}
试题3:小R的随机播放顺序
问题描述:
小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌,播放后将其从歌单中移除。如果歌单中还有歌曲,则会将当前第一首歌移到最后一首。这个过程会一直重复,直到歌单中没有任何歌曲。
例如,给定歌单 [5, 3, 2, 1, 4],真实的播放顺序是 [5, 2, 4, 1, 3]。
保证歌曲中的id两两不同。
from collections import deque
def solution(n: int, a: list) -> list:
# 创建一个结果列表来存储最终的播放顺序
result = []
# 使用 deque 来模拟播放过程
queue = deque(a)
# 遍历队列,按照题目描述的规则进行操作
while queue:
# 从队列头部取出一个元素,并将其加入结果列表
result.append(queue.popleft())
# 如果队列中还有元素,则将当前队列头部的元素移到队列尾部
if queue:
queue.append(queue.popleft())
return result
if __name__ == '__main__':
print(solution(n = 5, a = [5, 3, 2, 1, 4]) == [5, 2, 4, 1, 3])
print(solution(n = 4, a = [4, 1, 3, 2]) == [4, 3, 1, 2])
print(solution(n = 6, a = [1, 2, 3, 4, 5, 6]) == [1, 3, 5, 2, 6, 4])
试题4:DNA序列编辑距离
问题描述:
小R正在研究DNA序列,他需要一个函数来计算将一个受损DNA序列(dna1)转换成一个未受损序列(dna2)所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。
def solution(dna1, dna2):
m, n = len(dna1), len(dna2)
# 创建一个 (m+1) x (n+1) 的二维数组 dp
dp = [[0] * (n + 1) for _ in range(m + 1)]
# 初始化 dp 数组的第一行和第一列
for i in range(m + 1):
dp[i][0] = i
for j in range(n + 1):
dp[0][j] = j
# 填充 dp 数组
for i in range(1, m + 1):
for j in range(1, n + 1):
if dna1[i - 1] == dna2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
# 返回 dp[m][n],即最少编辑步骤
return dp[m][n]
if __name__ == "__main__":
# 你可以添加更多测试用例
print(solution("AGCTTAGC", "AGCTAGCT") == 2)
print(solution("AGCCGAGC", "GCTAGCT") == 4)
试题5:小U的数字插入问题
问题描述:
小U手中有两个数字 a 和 b。第一个数字是一个任意的正整数,而第二个数字是一个非负整数。她的任务是将第二个数字 b 插入到第一个数字 a 的某个位置,以形成一个最大的可能数字。
你需要帮助小U找到这个插入位置,输出插入后的最大结果。
def solution(a: int, b: int) -> int:
# 将数字转换为字符串
str_a = str(a)
str_b = str(b)
# 初始化最大值
max_num = 0
# 遍历插入位置
for i in range(len(str_a) + 1):
# 尝试将 str_b 插入到 str_a 的第 i 个位置
new_num_str = str_a[:i] + str_b + str_a[i:]
# 将新字符串转换为整数
new_num = int(new_num_str)
# 更新最大值
if new_num > max_num:
max_num = new_num
return max_num
if __name__ == '__main__':
print(solution(76543, 4) == 765443)
print(solution(1, 0) == 10)
print(solution(44, 5) == 544)
print(solution(666, 6) == 6666)