Skip to content

Latest commit

 

History

History
195 lines (157 loc) · 4.75 KB

File metadata and controls

195 lines (157 loc) · 4.75 KB
comments difficulty edit_url tags
true
中等
数组
二分查找
矩阵

English Version

题目描述

给定一个包含 奇数 个整数的 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)$

Python3

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)

Java

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;
    }
}

C++

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;
    }
};

Go

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
}