赞
踩
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
}
};
分析数据
(1)数据量。从下面可以看出:
(2)数据特性
思路
问题
思路:要求小于等于target的
从这里我们可以发现一个性质,
问题
代码
class Solution { struct Info{ int near; int num; Info(int num, int near) : num(num), near(near){ } }; static Info noMoreNum(vector<vector<int>>& matrix, int value){ int near = INT16_MIN; int num = 0; int N = matrix.size(), M = matrix[0].size(); int row = 0, col = M - 1; while (row < N && col >= 0){ if(matrix[row][col] <= value){ near = std::max(near, matrix[row][col]); num += col + 1; row++; }else{ col--; } } return { num, near}; } public: int kthSmallest(vector<vector<int>>& matrix, int k) { int N = matrix.size(), M = matrix[0].size(); int left = matrix[0][0], right = matrix[N - 1][M - 1]; int ans = 0; while (left <= right){ int mid = left + ((right - left) >> 1); // <=mid 有几个 <= mid 在矩阵中真实出现的数,谁最接近mid Info info = noMoreNum(matrix, mid); if(info.num < k){ left = mid + 1; }else{ ans = info.near; right = mid - 1; } } return ans; } };
复杂度: O((N + M) * log(max - min))
思路
在整个矩阵中,每次弹出矩阵中最小的值,第k个被弹出的就是我们想要的数据
那么,每次弹出矩阵中最小的值呢?
当我们看到下面这个有序矩阵时,我们知道左上角的数字是整个矩阵最小的。
但是弹出它之后,如何能够保证接下来每一次都还能找到全矩阵中最小的值呢?
解决这个问题的关键,在于维护一组“最小值候选人”。
需要保证的是最小值必然从这组候选人中产生,于是每次只要从候选人中弹出一个最小的就可以了。
我们来选择第一组候选人,在这里可以选择第一列,因为每一个数字都是其对应行的最小值,全局最小必然在其中
第一次弹出很简单,将左上角的1弹出即可。
1弹出之后,我们如何找到下一个候选人呢?
很简单,刚才弹出的位置右移一格就行了,这样不是还能保证候选人链表中每一个数字都是每一行的最小值吗,那全局最小值必然在其中!
我们每次弹出候选人当中的最小值,然后把上次弹出候选人的右边一个补进来,就能一直保证全局最小值在候选人列表中产生,
说白了就是每行一路,五路归并,用堆比较最小值。所以上下的顺序是没有用到,只用到左右的顺序
class Solution { struct Element { int val; int x; int y; Element(int val, int x, int y) : val(val), x(x), y(y) { } // 方法二定义pq 需要重载 operator> bool operator> (const Element &other) const { return this->val > other.val; } }; public: int kthSmallest(vector<vector<int>>& matrix, int k) { int N = matrix.size(), M = matrix[0].size(); // 定义pq方法一:用自定义的比较 // auto comp = [](Element e1, Element e2) { return e1.val > e2.val; }; // priority_queue<Element, vector<Element>, decltype(comp)> pq (comp); // 用优先队列表示最小堆 // 定义pq方法二:在 Element 中重载 operator>,然后用内置的std::greater priority_queue<Element, vector<Element>, std::greater<Element>> pq; // 初始化:将 matrix 的第一列加入 pq 作为初始的「最小候选值」列表 for (int r = 0; r < N; ++r) { Element e(matrix[r][0], r, 0); pq.push(e); } // 弹出前 k-1 小的值 for (int i = 0; i < k - 1; ++i) { Element top = pq.top(); pq.pop(); if (top.y != N - 1) { // 当前 (top.x, top.y) 的右边还有数字,将它右边的数 push 到优先队列中 Element e(matrix[top.x][top.y + 1], top.x, top.y + 1); pq.push(e); } } return pq.top().val; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。