📜  两个给定数组之间的最大非交叉线数(1)

📅  最后修改于: 2023-12-03 14:48:53.372000             🧑  作者: Mango

两个给定数组之间的最大非交叉线数

问题描述

有两个长度分别为 n 和 m 的整数数组 nums1 和 nums2,两个数组中的所有整数均在 −10^9 至 10^9 之间。将这两个数组画在一个二维平面上,其中 nums1 被画在 x 轴上而 nums2 被画在 y 轴上。找到并返回 每对相交且不相交的直线的 最大数量。如果两条直线在相同的位置,则不考虑这条直线。

问题分析

本题为最大匹配问题,可以使用经典的匈牙利算法求解。

首先进行预处理,对 nums1 和 nums2 分别排序,并去除重复元素。为了方便计算,可以将 nums1 和 nums2 转化为一个从 1 开始的正整数数组。

接下来考虑建立二分图和求解最大匹配。将 nums1 和 nums2 分别作为二分图的两个部分,二分图中的每个节点代表一个数。

对于每个 nums1 中的元素,它可以匹配 nums2 中的某个元素,我们可以将 nums1 中的每个元素与 nums2 中的每个元素进行比较,找到一个最大的 j,使得 nums1[i]<nums2[j],那么 nums1[i] 与 nums2[j-1] 就可以匹配。接着递归调用匈牙利算法,将 nums2[j-1] 匹配给 nums1[i],并继续查找 nums1 中还未匹配的元素。

匈牙利算法结束后,得到的就是 nums1 和 nums2 之间的最大非交叉线数。

代码实现
def maxUncrossedLines(nums1: List[int], nums2: List[int]) -> int:
    nums1 = sorted(set(nums1))
    nums2 = sorted(set(nums2))

    # 构建二分图的邻接矩阵
    n, m = len(nums1), len(nums2)
    graph = [[0] * m for _ in range(n)]
    for i in range(n):
        for j in range(m):
            if nums1[i] == nums2[j]:
                graph[i][j] = 1

    # 递归查找增广路
    def dfs(u: int, p: List[int], visit: List[bool]) -> bool:
        for v in range(m):
            if graph[u][v] and not visit[v]:
                visit[v] = True
                if p[v] == -1 or dfs(p[v], p, visit):
                    p[v] = u
                    return True
        return False

    # 匈牙利算法
    ans = 0
    p = [-1] * m
    for u in range(n):
        visit = [False] * m
        if dfs(u, p, visit):
            ans += 1

    return ans
复杂度分析

该算法的时间复杂度为 O(NMK),其中 K 表示匈牙利算法递归的深度,即最大的增广路长度。当 nums1 和 nums2 中没有重复元素时,K 的最大值为 min(N,M),此时时间复杂度为 O(NMmin(N,M))。在实际的题目中,由于 nums1 和 nums2 中均可能存在重复元素,因此实际运行时间会更快。