题目描述
给定一个包含 奇数 个整数的 m x n
矩阵 grid
,其中每一行按 非递减 的顺序排序,返回矩阵的 中位数。
你必须以 O(m * log(n))
的时间复杂度来解决这个问题。
示例 1:
输入: grid = [[1,1,2],[2,3,3],[1,3,4]]
输出: 2
解释: 矩阵的元素按顺序排列为 1,1,1,2,2,3,3,3,4。中位数是 2。
示例 2:
输入: grid = [[1,1,3,3,4]]
输出: 3
解释: 矩阵的元素按顺序排列为 1,1,3,3,4。中位数是 3。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 500
m
和 n
都是奇数。
1 <= grid[i][j] <= 106
grid[i]
按非递减顺序排序
解法
方法一:两次二分查找
中位数实际上是排序后第 $target = \left \lceil \frac{m\times n}{2} \right \rceil$ 个数。
我们二分枚举矩阵的元素 $x$,统计网格中大于该元素的个数 $cnt$,如果 $cnt \ge target$,说明中位数在 $x$ 的左侧(包含 $x$),否则在右侧。
时间复杂度 $O(m\times \log n \times log M)$,其中 $m$ 和 $n$ 分别为网格的行数和列数,而 $M$ 为网格中的最大元素。空间复杂度 $O(1)$。
| class Solution:
def matrixMedian(self, grid: List[List[int]]) -> int:
def count(x):
return sum(bisect_right(row, x) for row in grid)
m, n = len(grid), len(grid[0])
target = (m * n + 1) >> 1
return bisect_left(range(10**6 + 1), target, key=count)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | class Solution {
private int[][] grid;
public int matrixMedian(int[][] grid) {
this.grid = grid;
int m = grid.length, n = grid[0].length;
int target = (m * n + 1) >> 1;
int left = 0, right = 1000010;
while (left < right) {
int mid = (left + right) >> 1;
if (count(mid) >= target) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
private int count(int x) {
int cnt = 0;
for (var row : grid) {
int left = 0, right = row.length;
while (left < right) {
int mid = (left + right) >> 1;
if (row[mid] > x) {
right = mid;
} else {
left = mid + 1;
}
}
cnt += left;
}
return cnt;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | class Solution {
public:
int matrixMedian(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
int left = 0, right = 1e6 + 1;
int target = (m * n + 1) >> 1;
auto count = [&](int x) {
int cnt = 0;
for (auto& row : grid) {
cnt += (upper_bound(row.begin(), row.end(), x) - row.begin());
}
return cnt;
};
while (left < right) {
int mid = (left + right) >> 1;
if (count(mid) >= target) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | func matrixMedian(grid [][]int) int {
m, n := len(grid), len(grid[0])
count := func(x int) int {
cnt := 0
for _, row := range grid {
left, right := 0, n
for left < right {
mid := (left + right) >> 1
if row[mid] > x {
right = mid
} else {
left = mid + 1
}
}
cnt += left
}
return cnt
}
left, right := 0, 1000010
target := (m*n + 1) >> 1
for left < right {
mid := (left + right) >> 1
if count(mid) >= target {
right = mid
} else {
left = mid + 1
}
}
return left
}
|