LeetCode 378. 有序矩阵中第 K 小的元素

161 阅读2分钟

378. 有序矩阵中第 K 小的元素

难度中等927

给你一个 n x n **矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。

你必须找到一个内存复杂度优于 O(n2) 的解决方案。

 

示例 1:

输入: matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
输出: 13
解释: 矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第 8 小元素是 13

示例 2:

输入: matrix = [[-5]], k = 1
输出: -5

 

提示:

  • n == matrix.length
  • n == matrix[i].length
  • 1 <= n <= 300
  • -109 <= matrix[i][j] <= 109
  • 题目数据 保证 matrix 中的所有行和列都按 非递减顺序 排列
  • 1 <= k <= n2

 

进阶:

  • 你能否用一个恒定的内存(即 O(1) 内存复杂度)来解决这个问题?
  • 你能在 O(n) 的时间复杂度下解决这个问题吗?这个方法对于面试来说可能太超前了,但是你会发现阅读这篇文章( this paper )很有趣。

通过次数117,465提交次数184,763

暴力就不说了

解法一:多路归并 需要借助优先队列实现

解法二:二分答案,一维的容器可以二分索引下标,二维的只能二分值,左上角最小,右下角最大,二分值 ,对于一个mid 小于等于mid的元素一定都在该矩阵的某个左上角部分,大于的在右下角。划线统计左上角元素的数量。

解法一代码: 借一张图就很明白了,实现了有序的查找元素,所以知道找到第K个。

image.png

class Solution {
public:
//多路归并的思路   最左边的一列肯定是整个矩阵最小的n个元素
//借助优先队列,每次取出最小的元素,扩展其右边的元素,加入优先队列
//可以实现有序的选出前k-1个元素
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        struct Point{
            int val,x,y;
            Point(int val,int x,int y): val(val), x(x), y(y) {}
            bool operator > (const Point &a) const {
                return this->val > a.val;
            }
        };

        priority_queue<Point, vector<Point>, greater<Point>> que;
        int n = matrix.size();
        for(int i=0; i<n; i++) {
            que.emplace(matrix[i][0], i, 0);
        }
        for(int i=0; i<k-1; i++) {
            Point now = que.top();
            que.pop();
            if(now.y != n - 1) {
                que.emplace(matrix[now.x][now.y + 1], now.x, now.y+1);
            }
        }
        return que.top().val;
    }
};

解法二:二维矩阵上的二分说实话我也是头一次做

image.png

class Solution{
public:
    bool check(vector<vector<int>>& matrix,int mid,int k,int n) {
        int i = n-1,j = 0,sum = 0;
        while(i >= 0 && j < n) {
            if(matrix[i][j] <= mid) {
                sum += i + 1;
                j++;
            }
            else i--;
        }
        return sum >= k;
    }

    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int n = matrix.size(),mid,ans;
        int left = matrix[0][0], right = matrix[n - 1][n - 1];
        while(left < right) {
            mid = left + right >> 1;
            if(check(matrix, mid, k, n)) right = mid;
            else left = mid + 1, ans = mid;
        }
        return left;
    }
};