关注我们,每天更新大厂最新笔试题解析
前言
文末给大家推荐一下我们的活动,针对校招笔面试全覆盖的全程真一对一的提高,参加活动前会给你安排一个全面的摸底,摸底后会针对你的情况进行分析和对于参加活动的介绍,然后你再决定是否参加!
华为这波真的没得说了,不能ak的要面壁思过啦!
在线做题链接:https://niumacode.com/
大模型训练显存优化算法:将张量释放策略取最小代价后,转化为变种的 0-1 背包问题,通过动态规划求解满足最小目标空间所需的最低总开销。 基于KNN的语音数据分类:核心为标准 KNN 算法的直接应用,通过计算待测向量与已知样本的欧氏距离并排序,提取最近的 K 个邻居进行多数表决来锁定最终类别。
21、大模型训练显存优化算法
在线做题链接:https://niumacode.com/
题目描述
在大模型训练中,为解决NPU显存不够用的情况,通常采用张量swap或者张量重计算的方式进行优化;张量swap是把张量的数据先搬到CPU,需要的时候,再从CPU搬回NPU;张量重计算是在需要张量的值时,在NPU上重新把张量的值计算出来。
假设把模型部署到NPU上,还需要 大小的存储空间,才能让大模型运行起来; 目前有 个候选张量,每个张量占用一定的存储空间; 个张量中的每个张量都可以进行swap或者重计算,swap和重计算分别对应不同的代价; 试着编写一段程序,从 个候选张量中选择合适的张量进行swap或者重计算,在代价最小的情况下,使得大模型能够运行起来(选择的张量和大于等于 )。
输入描述
第一行为1个整数 $m(0<m<10000)$,表示需要的存储空间大小 第二行为1个整数="" $n(0<n<10000)$,表示候选张量的个数="" 第三行有="" $n$="" 个处于区间="" $[1,="" 10000]$="" 之内的整数,表示="" 个候选张量的存储空间大小="" 第四行有="" 100000]$="" 个候选张量swap的代价="" 第五行有="" 个候选张量重计算的代价<="" p="">
输出描述
如果没有找到合适的解,输出error;否则,输出最小代价(行尾没有空格)。
样例1
输入:
1053 4 5 6 71 2 3 5 52 3 4 5 6输出:
6解释:需要的存储空间是10; 候选张量长度分别为3,4,5,6,7; 张量长度组合 ,,,,,,...都大于等于10,满足运行的基本条件; 对于 来说,3的最小代价是1,7的最小代价是5, 的最小代价是6,经过其他组的比较,达成目标的最小代价是6,所以输出6。
思路与代码
本题的本质是一个变种的 0-1 背包问题。 我们需要从 个张量中选择一部分,使得它们的空间之和 ,同时要求总代价最小。
代价转换:每个张量只能选一种优化方式(swap 或重计算),为了使总代价最小,每个张量应直接取两者的最小值:。 状态定义: 表示腾出至少 大小空间所需要的最小代价。 目标:求 。
题目给出了每个张量 swap 和重计算的两种代价。由于每个张量一旦被选中用于释放空间,我们肯定会选择其中更便宜的那种方式。 因此,我们将输入压缩为一组 (size, cost) 对,其中 。
传统的 0-1 背包通常是“不超过容量 的最大价值”,而本题是“空间不少于 的最小代价”。
如果选择的张量总空间 ,它同样满足运行要求。 为了防止 DP 数组过大,我们将所有空间大于等于 的状态全部更新到 。
使用一维数组进行优化,防止重复选择同一张量(0-1 背包特性)。
初始化:,其余 。 遍历张量:对于每一个张量 : 新空间 。 如果 ,则更新 。 如果 ,则更新 。 逆序遍历空间(从当前已达到的最大空间 向 遍历):
import sysfrom collections import defaultdictdef solve(): m = int(sys.stdin.readline().strip())# 读取第二行 n n = int(sys.stdin.readline().strip())# 逐行读取并映射为整数列表 sizes = list(map(int, sys.stdin.readline().strip().split())) swaps = list(map(int, sys.stdin.readline().strip().split())) recomps = list(map(int, sys.stdin.readline().strip().split()))# 剪枝:如果所有的张量空间全加起来依然无法满足 m,直接返回 errorif sum(sizes) < m:print("error")return# 将具有相同大小的张量代价归类,并选用 swap 和 recompute 中代价较小者 size_costs = defaultdict(list)for i in range(n): min_cost = swaps[i] if swaps[i] < recomps[i] else recomps[i] size_costs[sizes[i]].append(min_cost)# 优化:剔除冗余张量 optimized_items = []for s, costs in size_costs.items(): costs.sort() # 按代价从小到大排序# 对于大小为 s 的张量,最多只需要用到 math.ceil(m / s) 个limit = (m + s - 1) // s# 只保留最便宜的 limit 个张量 optimized_items.extend([(s, c) for c in costs[:limit]])# 初始化 DP 数组,dp[j] 代表腾出 j 大小空间花费的最小代价 dp = [float('inf')] * (m + 1) dp[0] = 0 max_j = 0 # 记录当前可以到达的最大空间,用于减少内层循环次数for s, c in optimized_items:# 0-1 背包需逆序遍历,防止同一个张量被计算多次for j in range(max_j, -1, -1):if dp[j] != float('inf'): nj = j + s val = dp[j] + c# 如果腾出的空间已经大于等于 m,统一记录在 dp[m] 中if nj >= m:if val < dp[m]: dp[m] = valelse:if val < dp[nj]: dp[nj] = val# 更新目前能到达的最大释放空间界限 max_j += sif max_j > m: max_j = m# 输出结果if dp[m] == float('inf'):print("error")else:print(dp[m])solve()22、基于KNN的语音数据分类
在线做题链接:https://niumacode.com/
题目描述
在终端穿戴场景中,往往涉及到用户和终端设备之间的语音交互,通常由用户唤醒相关的设备并进行语音命令控制设备完成相应的操作,设备在收到语音命令时会对用户的意图进行识别,例如识别“拍照”“摄像”等意图,从而进行对应的操作。 要求使用KNN算法对用户输出的语音特征进行分类: 语音片段经过特征提取后是一个3维的向量 所有距离使用欧式距离公式计算,即对于两个N维向量
两个向量间的距离为:
输入描述
第一行:正整数 N和K,分别表示给定的已知语音特征向量的数量和邻居数量K 第2~13行:已知语音的特征向量和label,其中最后一位表示类别label 第14行:待分类的语音特征向量
输出描述
给出待分类语音的类别,该值为正整数,在输入给定范围内.
样例1
输入:
10 30.5 0.3 0.4 00.6 0.2 0.5 00.4 0.3 0.3 00.7 0.4 0.6 02.1 2.3 2.2 12.3 2.2 2.4 12.2 2.4 2.3 14.5 4.3 4.4 24.4 4.5 4.6 24.6 4.4 4.5 22.2 2.1 2.3输出:
1解释:待分类的语音特征向量为 (2.2, 2.1, 2.3)。计算其与所有已知向量的欧式距离后,最近的 3 个邻居分别是:
(2.1, 2.3, 2.2) 类别 1 (2.3, 2.2, 2.4) 类别 1 (2.2, 2.4, 2.3) 类别 1 这 3 个邻居都属于类别 1,因此待分类向量被判定为类别 1。
样例2
输入:
12 41 0.9 1 10.8 0.9 0.7 11.3 1 1.2 11.2 0.9 1 12 2.2 2.1 22.3 2.2 2 22 2.2 1.9 21.9 2.2 2.1 23.1 3.1 3 32.8 2.9 3.1 32.9 3 3.2 33.1 3 3.1 32.2 1.2 1.9输出:
2解释:与2.2, 1.2, 1.9 最近的4个邻居中,类别最多的是2,故被分类为2
思路与代码
本题的核心在于实现 KNN(K-Nearest Neighbors,K-最近邻) 分类算法。其本质逻辑是:“物以类聚”。对于一个待分类的样本,我们在已知数据集中寻找距离它最近的 个样本,查看这些邻居中哪个类别出现的次数最多,就将该样本归为哪一类。
要解决该问题,我们需要按照以下逻辑步步深入:
第一步:定义“相似度”——距离度量题目明确要求使用欧氏距离。对于两个 3 维特征向量 和 ,我们需要计算它们在空间中的绝对距离。公式为:
这是判断“谁是邻居”的唯一标准。
第二步:全局对比——寻找近邻当输入一个待分类的向量时,它在特征空间中是一个孤立的点。为了找到邻居,我们需要将该点与已知数据集中的 个样本逐一计算距离。计算完成后,我们会得到 个“距离-标签”对。
第三步:筛选与排序——锁定前 K 个仅仅算出距离是不够的,我们需要找到“最近”的。因此,需要对所有计算出的距离进行升序排列。排序后,取前 个样本,这 个样本就是参与决策的“投票团”。
第四步:多数表决——确定类别在锁定的 个邻居中,统计各个类别(Label)出现的频率。例如,若 ,邻居标签为
[1, 1, 2],则类别1出现的次数最多。根据多数表决原则,最终判定待分类向量属于类别1。
时间复杂度:
计算距离:需要遍历 个样本,每个样本涉及 3 维运算,复杂度为 。 排序:对 个距离进行排序,复杂度为 。 统计表决:遍历 个标签,复杂度为 。 总复杂度约为 ,在题目给定的数据规模下表现优秀。 空间复杂度:,用于存储已知样本的特征与标签。
import sysimport mathfrom collections import Counterdef main():# 解析给定的样本数量 N 和邻居数量 K N, K = map(int, sys.stdin.readline().strip().split()) known_data = []# 循环读取 N 行已知语音的特征向量和 labelfor _ in range(N): line = sys.stdin.readline().strip().split()# 题目说明最后一位是 label,前面的都是特征向量 features = tuple(map(float, line[:-1])) label = int(line[-1]) known_data.append((features, label))# 读取最后一行:待分类的语音特征向量 target_line = sys.stdin.readline().strip().split() target_vector = tuple(map(float, target_line))# 计算待分类向量与所有已知向量之间的欧式距离 distances = []for features, label in known_data:# 使用生成器表达式和 math.sqrt 计算欧式距离# zip() 会将待分类向量与已知向量的对应维度一一配对 dist = math.sqrt(sum((x - y) ** 2 for x, y in zip(features, target_vector))) distances.append((dist, label))# 按照欧式距离进行升序排序 (从小到大) distances.sort(key=lambda item: item[0])# 截取前 K 个距离最近的邻居,并提取出它们的 label top_k_labels = [label for dist, label in distances[:K]]# 统计这 K 个邻居中,各个 label 出现的频次 label_counts = Counter(top_k_labels)# 选出出现频次最高的一个 label (most_common 返回的是列表,例如:[(label, count)]) predicted_class = label_counts.most_common(1)[0][0]# 输出最终分类结果print(predicted_class)main()我们是一个针对技术岗(前后端开发、测试、测开、大数据开发、大模型、ai等相关岗位)校招一对一进阶提高的工作室。我们从2020年2月份开始,迄今整整六年的时间,带领900+学员斩获4000+中大厂offer,参加活动的同学人均5个中大厂offer以上,以下是我们活动内容的介绍! 万诺coding
我们主要是针对有一定基础的同学提供全程一对一笔试、面试辅导,针对每个同学不同的情况定制内容,包括但不限于“笔试及面试算法”/“基础八股/“项目及实习梳理”/“面试技巧”/“面试复盘”等内容。
摸底测试:如果有兴趣深入了解我们的活动,需要先参加我们的“摸底测试”(类似面试),方便我们了解你的具体情况(主要是code能力和计算机素养),定制出相应的辅导计划。摸底测试后,我们会定制化一个针对性的提高计划。然后你再考虑是否参加我们的活动。
承诺保offer:通过摸底测试后,我们会针对每个同学的情况给定一个“保offer”计划。然后同学可以根据自己的实际情况考虑参不参加我们的活动。
有兴趣的同学可以扫码添加我们的微信(whynotlab)
