给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
说明:
你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n2 。
--------------------------------------------------------------------------------------------------------------------------------------------------
我通过这道题了解了,二分查找的算法怎么写,之前只在书上见过,并没有实际的应用过,今天是第一次看到怎么应用在题目中。。。。。。。
由于每行每列的方向都是递增的。 这也是一个二分写法的题目的一个特点,表内元素必须有序。
AC:
class Solution {
public:
bool fun(long long midd,vector<vector<int>>& matrix, long long k,long long n)
{
int sum=0;
for (int i=0;i<n;i++)
{
int l=0;
int r=n-1;
int ans=0; // ans是用来记录每行中比midd小的元素的数量。
while(l<=r) //闭区间不问空的条件是左界不大于右界,即(l<=r),如果是左闭右开区间,不空的条件是l<r
{
int mid=(l+r)/2;
if (matrix[i][mid]<midd)
{
ans=mid+1; //因为每行元素都是递增的,那么mid+1就表示在这一行中比midd小的元素的数量。
l=mid+1;
}
else
r=mid-1;
}
sum=sum+ans;
}
return k>sum; //如果sum<k(即midd的排名比k小),说明midd猜的比较小。在kith那个函数中的左边界就要mid+1(即变 // 大)因为在矩阵中,越往右下角越大。
}
int kthSmallest(vector<vector<int>>& matrix, int k) {
long long n=matrix.size();
long long l=matrix[0][0];
long long r=matrix[n-1][n-1];
long long ans=0;
while(l<=r)
{
long long mid=(l+r)/2;
if (fun(mid,matrix,k,n)) //mid与sum是一个正相关
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
return (int)ans;
}
};
如果用STL中的库函数的话,那么可以写成
- 两个迭代器相减代表的是两个之间的距离。
- lower_bound() 返回一个迭代器,指向第一个不小于目标val的元素。
- upper_bound()返回一个迭代器,指向第一个大于目标val的元素。
AC:
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
vector<vector<int>> mm=matrix; //偷懒的写法,matrix觉得写的麻烦。
int n=mm.size();
long long l=mm[0][0];
long long r=mm[n-1][n-1];
long long mid=0;
while(l<=r)
{
mid=(l+r)/2; //写到这明白了为什么许多人写成 l+(r-l)/2 这样不容易溢出,如果直接(l+r)/2,当l=r=2000000000时
//虽然这个时候l和r都没有超出int的界限,但是l+r 却溢出,导致RE,这时可以l,r,mid全改为long long 。
int cnt1=0;
int cnt2=0;
for (int i=0;i<n;i++)
{
auto m=mm[i];
cnt1=cnt1+lower_bound(m.begin(),m.end(),mid)-m.begin(); //upper_bound() 这两个迭代器相减的结果的数值是比 //mid小的元素的个数。
cnt2=cnt2+upper_bound(m.begin(),m.end(),mid)-m.begin(); // upper_bound() 这两个迭代器相减的结果的数值是不 //小于mid的元素个数。
}
if (k>cnt1&&k<=cnt2)
return mid;
if (k>cnt2)
l=mid+1;
else
r=mid-1;
}
return mid;
}
};
看了好几遍终于懂了一点,抓紧把理解的写下来。最近感觉好累,最近的事情太多了。