介绍
豆包青训营是由字节跳动和稀土掘金社区共同发起的技术培训和人才选拔项目,主要面向在校大学生。该项目的目标是培养具有职业竞争力的优秀开发工程师,并提供全程免费的课程,不收取任何费用。
课程内容和方向
豆包青训营的课程涵盖前端、后端和AI方向。在这个飞速发展的AI时代,学员将与豆包MarsCode团队一起深入探索技术领域,学习和运用AI,提高编程效率。此外,课程还包括大数据方向,适合对大数据感兴趣的学员学习,
本文提供训练营试题解析供参考
试题1:禁着点方案数
问题描述:
def solution(n: int, a: list, s: int) -> int:
# 将禁着点数组转换为集合,以便快速查找
forbidden_set = set(a)
# 初始化计数器
count = 0
# 遍历所有可能的 x 值
for x in range(1, s):
y = s - x
# 检查 x 和 y 是否都不在禁着点集合中
if x not in forbidden_set and y not in forbidden_set:
# 如果满足条件,增加计数器的值
count += 1
return count
if __name__ == '__main__':
print(solution(3, [1, 2, 3], 10) == 3)
print(solution(2, [5, 9], 15) == 10)
print(solution(4, [1, 6, 9, 4], 13) == 6)
试题2:粮食分配的可能性计算
问题描述:
粮食公司需要将n吨粮食分配给若干分销商,每个分销商能够获得的粮食数量等于将n除以分销商数量,向下取整。问题是,计算在可能的分销商数量中,分销商获得的不同粮食数量有多少种可能。
例如,如果粮食总量为5吨,当分销商数量为1时,分销商获得5吨;当分销商数量为2时,分销商获得2吨;当分销商数量为3、4、5时,分销商获得的粮食依次为1吨。这样,不同的分配方案有3种可能。
def solution(n: int) -> int:
# 使用一个集合来存储不同的分配结果
unique_allocations = set()
# 遍历所有可能的分销商数量
for distributors in range(1, n + 1):
# 计算每个分销商获得的粮食数量
allocation = n // distributors
# 将分配结果添加到集合中
unique_allocations.add(allocation)
# 返回集合的大小,即不同的分配方案的数量
return len(unique_allocations)
if __name__ == '__main__':
print(solution(5) == 3)
print(solution(7) == 4)
print(solution(10) == 5)
试题3:装饰品丑陋值最小化问题
问题描述:
小M在整理桌子上的装饰品时,发现高度差异过大的装饰品放在一起会显得不美观。她希望通过交换装饰品的位置,使得它们的高度变化更加平滑,从而最小化整体的丑陋值。装饰品的丑陋值定义为相邻装饰品高度差的绝对值之和。小M可以任意交换装饰品的位置,目标是找到一种装饰顺序,使得丑陋值达到最小。
例如:当三个装饰品的高度分别为 3, 1, 2 时,通过交换它们的顺序,可以将高度排列为 1, 2, 3,此时丑陋值为 |1-2| + |2-3| = 2,这是最优解。
def solution(n: int, a: list) -> int:
# 对数组进行排序
sorted_a = sorted(a)
# 初始化丑陋值
ugly_value = 0
# 计算相邻元素的差值之和
for i in range(1, n):
ugly_value += abs(sorted_a[i] - sorted_a[i - 1])
return ugly_value
if __name__ == '__main__':
print(solution(3, [3, 1, 2]) == 2)
print(solution(5, [10, 20, 30, 5, 15]) == 25)
print(solution(4, [100, 200, 50, 150]) == 150)
试题4:计算“好数组”的数量
问题描述:
def solution(n: int, m: int) -> int:
MOD = 10**9 + 7
# 递归生成所有可能的数组
def generate_arrays(current_index, current_sum):
# 如果已经生成了长度为 n 的数组
if current_index == n:
# 检查数组的和是否是 n 的倍数
if current_sum % n == 0:
return 1
else:
return 0
count = 0
# 当前元素 a_i 必须是 i 的倍数,且在 1 到 m 之间
for value in range(current_index + 1, m + 1, current_index + 1):
# 递归生成下一个元素
count += generate_arrays(current_index + 1, current_sum + value)
count %= MOD
return count
# 从第一个元素开始生成数组
return generate_arrays(0, 0)
if __name__ == '__main__':
print(solution(3, 4) == 3)
print(solution(4, 6) == 8)
print(solution(5, 5) == 2)
试题5:连续空闲内存合并管理
问题描述:
小M设计了一个操作系统的内存管理模块,其中内存以连续编号的方式分配,每块内存的大小为1个单位。当用户释放内存后,系统需要将相邻的空闲内存合并为一个连续的大块,返回其中最大的连续内存块的起始位置和内存块数。如果存在多个连续内存块大小相同的情况,则返回编号最小的内存块信息。
例如,输入 [1,3,2,5] 表示释放了编号为1、3、2、5的内存块。在合并之后,编号为 1,2,3 的内存可以合并为一块大小为3的内存块,起始编号为1。
def solution(released_memory: list) -> list:
# 1. 对释放的内存块进行排序
released_memory.sort()
# 初始化变量
max_start = 0
max_length = 0
current_start = released_memory[0]
current_length = 1
# 2. 遍历排序后的内存块,合并相邻的内存块
for i in range(1, len(released_memory)):
if released_memory[i] == released_memory[i-1] + 1:
# 如果当前块与前一块相邻,增加当前块的长度
current_length += 1
else:
# 如果当前块与前一块不相邻,检查是否需要更新最大块
if current_length > max_length:
max_length = current_length
max_start = current_start
# 重置当前块的起始位置和长度
current_start = released_memory[i]
current_length = 1
# 3. 检查最后一个块是否是最大块
if current_length > max_length:
max_length = current_length
max_start = current_start
return [max_start, max_length]
if __name__ == '__main__':
print(solution([1, 3, 2, 5]) == [1, 3])
print(solution([2, 4, 3, 7, 6]) == [2, 3])
print(solution([5, 6, 10, 11, 12]) == [10, 3])
试题6:黑产行为序列识别
问题描述:
小S 和小M 正在研究一种黑产行为序列识别技术。网络黑色产业链是指使用互联网技术进行非法活动,例如网络攻击、窃取信息、诈骗等。为了保护用户和平台的安全,识别黑产行为的序列是十分关键的一步。
他们的任务是:给定一个行为序列S,表示为一个字符串,以及一个识别模式P。如果模式P是序列S的子序列,则说明存在匹配的黑产行为。
现在,给定多个序列S和对应的识别模式P,找出序列中出现匹配模式的次数,结果需要对10^9+7取模。
def solution(S: str, P: str) -> int:
MOD = 10**9 + 7
len_S = len(S)
len_P = len(P)
# 创建一个 (len_P + 1) x (len_S + 1) 的二维数组 dp
dp = [[0] * (len_S + 1) for _ in range(len_P + 1)]
# 初始化 dp[0][j] = 1,表示空模式在任何字符串中都匹配一次
for j in range(len_S + 1):
dp[0][j] = 1
# 填充 dp 数组
for i in range(1, len_P + 1):
for j in range(1, len_S + 1):
if P[i - 1] == S[j - 1]:
# 如果当前字符匹配,则加上前一个字符匹配的情况
dp[i][j] = (dp[i - 1][j - 1] + dp[i][j - 1]) % MOD
else:
# 如果当前字符不匹配,则继承前一个字符匹配的情况
dp[i][j] = dp[i][j - 1]
# 返回 P 在 S 中作为子序列出现的次数
return dp[len_P][len_S]
if __name__ == '__main__':
print(solution("ABC", "A") == 1)
print(solution("AABCCD", "CCD") == 1)
print(solution("AABCCD", "C") == 2)