📅  最后修改于: 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