目录
378. 有序矩阵中第K小的元素 M
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
思路一:堆
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
priority_queue<int> pq;
for (int i = 0; i < matrix.size(); ++i) {
for (int j = 0; j < matrix[0].size(); ++j) {
pq.push(matrix[i][j]);
if (pq.size() > k) pq.pop();
}
}
return pq.top();
}
};
思路二:二分法 时间复杂度:O(nlgn*lgX),其中X为最大值和最小值的差值
矩阵最左上角为最小值,最右下角为最大值,我们在此范围内进行二分搜索,取中间数mid,然后在每行中查找mid,
这里使用upper_bound,在每行查找第一个大于mid的元素,
如果目标数比该行的尾元素大,则upper_bound返回该行元素个数,
如果目标数比改行第一个元素小,则uppper_bound返回0,
遍历完所有行可以确定mid是第几小的数,然后与k进行比较,进行二分查找,left和right最终相等,会变为数组中第k小的数。
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int left = matrix[0][0], right = matrix.back().back();
while (left < right) {
int mid = left + (right - left) / 2, cnt = 0;
for (int i = 0; i < matrix.size(); ++i) {
cnt += upper_bound(matrix[i].begin(), matrix[i].end(), mid) - matrix[i].begin();
}
if (cnt < k) left = mid + 1;
else right = mid;
}
return left;
}
};
思路二:优化 时间复杂度:O(nlgX)
因为:每行和每列元素均按升序排序 ,
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int left = matrix[0][0], right = matrix.back().back();
while (left < right) {
int mid = left + (right - left) / 2;
int cnt = search_less_equal(matrix, mid);
if (cnt < k) left = mid + 1;
else right = mid;
}
return left;
}
int search_less_equal(vector<vector<int>> &matrix, int target) { //O(n)
int n = matrix.size(), i = n - 1, j = 0, res = 0;
while (i >= 0 && j < n) {
if (matrix[i][j] <= target) {
res += i + 1;
++j;
} else {
--i;
}
}
return res;
}
};
668. 乘法表中第k小的数 H
几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第k小的数字吗?
给定高度m 、宽度n 的一张 m * n的乘法表,以及正整数k,你需要返回表中第k 小的数字。
例 1:
输入: m = 3, n = 3, k = 5
输出: 3
解释:
乘法表:
1 2 3
2 4 6
3 6 9
第5小的数字是 3 (1, 2, 2, 3, 3). O(m*logmn)
class Solution {
public:
int len(int m, int n, int x){
int cnt=0;
for(int i=1;i<=m;i++){
cnt+=min(n,x/i);
}
return cnt;
}
int findKthNumber(int m, int n, int k) {
int l=1;
int r=m*n+1;
while(l<r){
int x=l+(r-l)/2;
if( len(m,n,x)>=k ) r=x;
else l=x+1;
}
return l;
}
};