本文收录于「最新最全华为OD机试真题(Python版)」专栏,手把手带你零基础教学华为OD机试。本题集提供最优题解思路,解题步骤,代码解析,复杂度分析及最优题解源码等,支持多语言题解,助你轻松拿捏OD机考,一举上岸!安利大家关注&&收藏&&订阅!题库正在疯狂收录中,up!up!up!!
提醒:拒绝一切代考/替考,违法必究!专栏所写题库均搜集于互联网,经过精心筛选和整理,结合数位十多年大厂实战经验资深大佬经验所撰,欢迎订阅。
订阅福利:一次订阅,可永久免费阅读,提供在线答疑解惑,后续题库更新皆可阅读使用!
如上题库均已同步更新至最新华为OD机试真题,赶紧操练起来吧~~
具体题目描述如下:
从一个 N*M (N≤M) 的矩阵中选出 N 个数,任意两个数字不能在同一行或同一列,求选出来的 N 个数中第 K 大的数字的最小
值是多少。
输入矩阵要求:1 ≤ K ≤ N ≤ M ≤ 150
输入格式:
N M K
N*M 矩阵
N*M 的矩阵中可以选出 M! / N!
种组合数组,每个组合数组种第 K大的数中的最小值。无需考虑重复数字,直接取 字典排序 结果
即可。
备注:
注意:结果是第K大的数字的最小值。
输入:
3 4 2
1 5 6 6
8 3 4 3
6 8 6 3
输出:
3
示例说明:
N*M的矩阵中可以选出 M!/N!种组合数组,每个组合数组种第 K大的数中的最小值;
上述输入中选出数组组合为:
1,3,6
1,3,3
1,4,8
1,4,3
上述输入样例中选出的组合数组有24种,最小数组为1,3,3,则第2大的最小值为3。
输入:
输出:
示例说明:
输入:
输出:
示例说明:
温馨提醒: 大家在参加华为OD机试时,切记不要仅仅死记硬背题解代码。真正的通过率取决于你对代码的理解能力。建议你在理解基本原理和逻辑的基础上,模仿并自己编写代码,这样才能更有效地应对机试。
题目要求从一个 N x M
的矩阵中选出 N
个数,要求选出的数字不能在同一行或同一列,并且要求找到这些选出的数字中第 K
大的数字的最小值。需要根据这个问题来构建一种方案,使得能够在所有的合法选择中找到最小的第 K
大值。
输入:
N
:选择的数字个数。M
:矩阵的列数。K
:需要找到的第 K
大的数字。N x M
大小,包含整数值。输出:
K
大的数字。题目解构:
N x M
的矩阵中选择 N
个数字,且要求这 N
个数字中每个数字必须来自不同的行和列。这样每个选择都可以看作是一个有效的矩阵选择。N
个数字中,我们要找出第 K
大的数字中的最小值。基本方法:
x
,然后通过构建一个图来检查是否可以在矩阵中选出 N
个不同行、不同列的数字,使得这些数字都小于或等于 x
。x
,通过构建一个二分图(bipartite graph
),通过图的最大匹配来判断是否能选出 N
个数字满足条件。具体地,我们通过DFS(深度优先搜索)来实现图中的匹配操作。详细步骤:
x
,构建一个二分图。图的每个节点表示矩阵中的行或列,如果某个数字小于等于 x
,则我们在该数字所在的行和列之间建立一条边。N
个不同行、不同列的数字。x
的范围,最终找到最小的 K
大数字。二分查找的收敛:
1
和矩阵中的最大值。通过反复测试中间值 mid
,判断是否可以选出 N
个数,如果可以则更新结果,并缩小搜索区间。N
个数。读取输入数据:
N
、M
、K
的值,然后读取矩阵数据。二分查找初始化:
l = 1
和 r = max(matrix)
,其中 max(matrix)
是矩阵中所有元素的最大值。构建二分图和最大匹配:
mid
,构建一个二分图,其中图的边表示矩阵中哪些行和列的交叉点可以选中。N
个数的值都小于等于 mid
。二分查找核心逻辑:
mid
是否满足条件。如果满足,则可能存在更小的解,将 r
设置为 mid - 1
,继续缩小搜索范围。否则,增大 mid
,继续查找更大的解。返回结果:
K
大数字,输出结果。根据如上题解思路,进行代码实战,大家请看如下,建议不要死记硬背代码,要理解其题型及实现思路,别担心,代码我都会给出超详细注释,你一定能看明白的。
class MatrixMatching:
def __init__(self, n, m, k, a):
self.n = n # 行数
self.m = m # 列数
self.k = k # 最大不匹配数量
self.V = 0
self.match = [-1] * 1000
self.used = [0] * 1000
self.Graph = [[] for _ in range(1000)] # 创建图
self.a = a # 输入的矩阵
def add_edge(self, u, v):
self.Graph[u].append(v)
self.Graph[v].append(u)
def dfs(self, v):
self.used[v] = 1
for u in self.Graph[v]:
w = self.match[u]
if w < 0 or (self.used[w] == 0 and self.dfs(w) == 1):
self.match[v] = u
self.match[u] = v
return 1
return 0
def bipartite_matching(self):
res = 0
for i in range(len(self.match)):
self.match[i] = -1
for v in range(self.V):
if self.match[v] < 0:
self.used = [0] * 1000 # 重置used数组
if self.dfs(v) == 1:
res += 1
return res
def check(self, x):
self.V = self.n + self.m + 1
for i in range(self.V):
self.Graph[i].clear()
for i in range(1, self.n + 1):
for j in range(1, self.m + 1):
if self.a[i][j] <= x:
self.add_edge(i, self.n + j)
return self.bipartite_matching() >= self.n - self.k + 1
def solve(self):
l, r = 1, 1000000000
ans = r
while l <= r:
mid = (l + r) >> 1
if self.check(mid):
r = mid - 1
ans = mid
else:
l = mid + 1
return ans
if __name__ == "__main__":
n, m, k = map(int, input().split()) # 输入n, m, k
a = [list(map(int, input().split())) for _ in range(n + 1)] # 输入矩阵a
matrix_matching = MatrixMatching(n, m, k, a)
result = matrix_matching.solve()
print(result) # 输出结果
时间复杂度:
O(log(maxValue))
,其中 maxValue
是矩阵元素的最大值,即 1,000,000,000。check
,需要运行 bipartite_matching
来检查最大匹配。bipartite_matching
采用的是深度优先搜索(DFS),在最坏情况下,每个节点需要进行匹配,DFS 的复杂度为 O(V + E)
,其中 V 是图中顶点的数量,E 是边的数量。对于每次匹配,DFS 最多要遍历整个图。由于图是稠密的,最坏情况下的复杂度为 O(n * m)
。O(log(maxValue) * n * m)
,其中 maxValue = 10^9
,n
和 m
分别是矩阵的行和列数。空间复杂度:
Graph
用来存储图的邻接表,空间复杂度是 O(V + E)
,其中 V 是顶点数,E 是边数。最大情况下,V 是 n + m + 1
,而每个节点可能与其他节点都有边,因此最大边数是 n * m
。match
, used
和矩阵 a
占用的空间为 O(n + m)
和 O(n * m)
,分别是常数和矩阵大小。O(n * m)
。类初始化:
MatrixMatching
类接受矩阵的大小 n
、m
和最大不匹配数量 k
,并初始化相关的数据结构:match
数组(用于存储匹配结果),used
数组(用于 DFS 遍历时标记节点是否已访问),Graph
(邻接表存储图的结构)以及矩阵 a
(输入的矩阵)。添加边:
add_edge(u, v)
方法用于在图中添加一条边,表示两个节点之间有连接。深度优先搜索(DFS):
dfs(v)
方法使用深度优先搜索来尝试为节点 v
寻找匹配。它递归地遍历图中与当前节点相连的节点,寻找未匹配或能够通过“增广路径”匹配的节点。二分查找与检查:
check(x)
方法通过二分查找确定最小的 x
值,使得可以在图中找到 n - k + 1
条匹配的边。它首先清空图的边,然后根据给定的 x
值添加满足条件的边,最后通过最大匹配算法验证是否能找到足够的匹配。主程序逻辑:
solve()
方法实现了二分查找的逻辑,查找最小的 x
,使得满足条件的匹配数量达到要求,并返回结果。输入输出:
map(int, input().split())
获取 n
、m
、k
的值,并通过嵌套列表解析输入矩阵 a
。ans
,即满足条件的最小 x
值。x
,使得在这个条件下,能找到足够的匹配。O(n * m)
的最大匹配算法。空间复杂度主要由图的存储和辅助数组构成,整体复杂度为 O(n * m)
。针对如上分享OD机试真题之外,这里我还开源全部OD机试原真题源码,供同学们一对一学习!对照每题都有题目号及详细代码注释。Gitee,例如题序号为1,则题解代码对应文件夹OD1,题序号为5,则题解代码对应文件夹OD5,以此类推,目的就是为了方便大家学习,一举上岸!(这里的题序号指专栏导航贴中表格一列的序号)
如果你还想学习更多相关OD真题题解,都建议直接毫不犹豫地学习此专栏「最新最全真题华为OD机试真题(全栈版)」,快速掌握Java、Python、C++、JavaScript、Go等多种热门语言详细解题,快速突破华为OD机试,实现350+高分目标。还将提供线上多端答疑交流,解决你的所有问题!
注意: 上述任意专栏一次订阅,获永久免费阅读权限,后续更新都能学习。
声明: 拒绝一切形式的代考,替考行为,务必诚信考试!!!本人所写题库均搜集于互联网。
我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主&最具价值贡献奖,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。
-End-