题目链接:点击这里
分析可见,给定次序直接求元素很困难,但给定元素求其次序范围相对简单。
由矩阵的行和列都有序递增可知,元素与次序单调、正相关。所以,考虑在 [ m a t r i x [ 0 ] [ 0 ] , m a t r i x [ n − 1 ] [ n − 1 ] ] [ \ matrix[0][0], matrix[n-1][n-1]\ ] [ matrix[0][0],matrix[n−1][n−1] ] 范围内二分找到第 K K K 大的元素 a n s ans ans
本题有重复数字,所以,次序是一个范围(即有左界和右界),难点就变成了check()函数如何判断当前的mid是否可接受。
AC代码:
class Solution {
public:
//问题转换为:给定mid,求其次序范围
bool check(int mid, vector<vector<int>>& matrix, int n, int k) {
//每一行都进行二分查找,遍历n行,sumL记录小于mid的个数
int sumL = 0;
for(int i = 0; i < n; i++)
{
int L = 0, R = n-1, ans = -1; //[L,R]
while(L<=R)
{
int mmid = L+(R-L)/2;
if(matrix[i][mmid] < mid)
{
ans = mmid;
L = mmid + 1;
}
else
R = mmid - 1;
}
sumL += (ans + 1);
}
//每一行都进行二分查找,遍历n行,sumR记录小于等于mid的个数
// int sumR = 0;
// for(int i = 0; i < n; i++)
// {
// int L = 0, R = n-1, ans = -1;
// while(L<=R)
// {
// int mmid = L+(R-L)/2;
// if(matrix[i][mmid] <= mid)
// {
// ans = mmid;
// L = mmid + 1;
// }
// else
// R = mmid -1;
// }
// sumR += (ans + 1);
// }
return sumL < k;
}
int kthSmallest(vector<vector<int>>& matrix, int k) {
int n = matrix.size();
int L = matrix[0][0], R = matrix[n-1][n-1]; //[L,R]
int ans = 0;
while(L<=R)
{
int mid = L+(R-L)/2;
if(check(mid, matrix, n, k))
{
ans = mid;
L = mid + 1;
}
else
R = mid - 1;
}
return ans;
}
};