题目:
给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
示例 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
1.暴力求解
把所有matrix里的值放进数列里,然后进行排序,返回k-1个的值
代码:
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
vector<int> res;
for (int i=0; i<matrix.size(); i++)
{
for (int j=0; j<matrix[0].size(); j++)
{
res.push_back(matrix[i][j]);
}
}
sort(res.begin(), res.end());
return res[k-1];
}
};
效率:
时间:O(n^2logn)
空间:O(n^2)
2. 优先队列和候选人
注意这个矩阵中每一行都是有序的。可以利用这个特征来选出k个最小值并返回第k个。用最小优先队列来储存这些候选值。
用一个数据结构来储存matrix的值和坐标。再创一个优先队列。因为第一列的值是整个矩阵中最小的那几个,先将第一列的值全部放入优先队列中。之后对这些值根据大小进行更新与替换。替换的值是弹出的值的右边的值,这样的话整个数列还是保存总体最小的那些值。最后放入k个值后,返回最顶上的。
代码:
这里是官方题解的代码:
class Solution {
public:
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;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/solution/you-xu-ju-zhen-zhong-di-kxiao-de-yuan-su-by-leetco/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
效率:
时间:O(klogn)
空间:O(n)
3. 二分查找
思路:
因为整个矩阵都是排序的,自然而然就回联想到用二分查找。在240.搜索二维矩阵2中也用到过这个算法。我们可以在这题上试试。区别是在240中需要找的值已经给你了,在这里并没有。我们需要慢慢搜索和逼近第k个小的值。
首先利用左上角和右下角的值算出中间值并数出矩阵中有几个是小于等于中间值的(count). 如果count<k,那么中间值比k小,否则比k大。通过这个调整范围和中间值,直到left=right。因为二分查找的性质,k会在left和right里,如果left=right,那意味着已经找到了解。这里的left和right是数值而不是坐标。最后返回right。
代码:
public int kthSmallest(int[][] matrix, int k) {
int row = matrix.length;
int col = matrix[0].length;
int left = matrix[0][0];
int right = matrix[row - 1][col - 1];
while (left < right) {
// 每次循环都保证第K小的数在start~end之间,当start==end,第k小的数就是start
int mid = (left + right) / 2;
// 找二维矩阵中<=mid的元素总个数
int count = findNotBiggerThanMid(matrix, mid, row, col);
if (count < k) {
// 第k小的数在右半部分,且不包含mid
left = mid + 1;
} else {
// 第k小的数在左半部分,可能包含mid
right = mid;
}
}
return right;
}
private int findNotBiggerThanMid(int[][] matrix, int mid, int row, int col) {
// 以列为单位找,找到每一列最后一个<=mid的数即知道每一列有多少个数<=mid
int i = row - 1;
int j = 0;
int count = 0;
while (i >= 0 && j < col) {
if (matrix[i][j] <= mid) {
// 第j列有i+1个元素<=mid
count += i + 1;
j++;
} else {
// 第j列目前的数大于mid,需要继续在当前列往上找
i--;
}
}
return count;
}
作者:jacksu1024
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/solution/er-fen-chao-ji-jian-dan-by-jacksu1024/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。