📌  相关文章
📜  在给定的逐行排序矩阵的所有行中找到一个公共元素(1)

📅  最后修改于: 2023-12-03 15:23:37.269000             🧑  作者: Mango

在给定的逐行排序矩阵的所有行中找到一个公共元素

问题描述

给定一个逐行排序的矩阵,每行无重复元素。请编写一个函数,找到其中所有的共同元素。

示例 1:

输入:
[
  [1, 2, 3, 4],
  [2, 3, 4, 5],
  [3, 4, 5, 6]
]
输出: [3, 4]
解决方案
方法一:暴力法

暴力法很简单,我们可以枚举每一列,然后判断这一列是否为公共元素。这种方法的时间复杂度是 $O(mn^2)$,其中 $m$ 和 $n$ 分别是矩阵的行数和列数。

class Solution:
    def commonElements(self, mat: List[List[int]]) -> List[int]:
        m, n = len(mat), len(mat[0])
        res = []
        for j in range(n):
            cnt = 0
            for i in range(m):
                if j == 0:
                    cnt = 1
                elif mat[i][j] in mat[i][:j]:
                    cnt += 1
            if cnt == m:
                res.append(mat[i][j])
        return res
方法二:二分法

因为每一行都是逐行排序的,所以我们可以对每一行进行二分查找,找到第一个大于等于该行的第一个元素的位置。我们可以将每一行的二分查找结果保存在一个 $m \times n$ 的数组中,然后对每一列的二分查找结果求交集,即可得到所有的公共元素。这种方法的时间复杂度是 $O(mn \log n)$,其中 $m$ 和 $n$ 分别是矩阵的行数和列数。

class Solution:
    def binarySearch(self, mat: List[List[int]]) -> List[List[int]]:
        m, n = len(mat), len(mat[0])
        pos = [[-1] * n for _ in range(m)]
        for i in range(m):
            left, right = 0, n - 1
            while left <= right:
                mid = (left + right) // 2
                if mat[i][mid] >= mat[i][0]:
                    pos[i][0] = mid
                    right = mid - 1
                else:
                    left = mid + 1
        return pos

    def commonElements(self, mat: List[List[int]]) -> List[int]:
        m, n = len(mat), len(mat[0])
        pos = self.binarySearch(mat)
        res = []
        for j in range(n):
            cnt = 0
            for i in range(m):
                if pos[i][0] == -1 or mat[i][pos[i][0]] != mat[0][j]:
                    break
                else:
                    cnt += 1
            if cnt == m:
                res.append(mat[0][j])
        return res
方法三:双指针

由于每一行都是逐行排序的,所以我们可以使用双指针来找到所有的公共元素。我们从第一行开始,用指针 $p_1$ 和 $p_2$ 分别指向第一行和第二行的开头,如果当前两个指针所指的值相等,就将它们都向右移动一位,否则就将值小的指针向右移动一位。然后,我们继续比较当前两个指针所指的值,直到找到公共元素或者遍历完所有的行为止。这种方法的时间复杂度是 $O(mn)$,其中 $m$ 和 $n$ 分别是矩阵的行数和列数。

class Solution:
    def commonElements(self, mat: List[List[int]]) -> List[int]:
        m, n = len(mat), len(mat[0])
        p = [0] * m
        res = []
        while p[0] < n:
            min_val = max(mat[i][p[i]] for i in range(m))
            cnt = 0
            for i in range(m):
                while p[i] < n and mat[i][p[i]] < min_val:
                    p[i] += 1
                if p[i] == n or mat[i][p[i]] > min_val:
                    break
                cnt += 1
            if cnt == m:
                res.append(min_val)
            p[0] += 1
        return res