题解:
1 直接排序。
最简单的方法,放到一维数组中,直接排序,时间复杂度为o((n^2)log(n^2)),空间复杂度为o(n^2),如果n>=1e4就会超时。
代码略:
2 堆排序。
这种方法是很一个很巧妙的方法。充分用到了矩阵的每一行和每一列都是有序的。首先将第一列放到堆中,然后取出第一个元素,这个元素一定是最小的,然后我们在考虑第二小的,第二小的要么是它右边的元素,要么是它下边的元素,由于它下边的元素已经在堆里面了,只需要把其右边的元素放到堆里即可。即每次取一个元素,然后将该元素的右边的元素放到堆中,注意堆排序要求堆顶元素最小。然后执行k次数就可以找到了
时间复杂度为o(klog(n))
空间复杂度为o(n)
由于在c++类中定义类/结构体还不太熟练,所以代码就没写。
3 二分法。
这种方法是最优的方法, 思路特别巧妙。注意矩阵的特点是每行每列都是有序的。所以对于每一个数我们总是可以找到一条线,该线可以把矩阵一分为二,左半部分是小于等于该数,右半部分是大于该数的。所以我们可以在时间复杂度为o(n)的情况下,来找到当前数在矩阵中有几个大于该数的,有几个小于等于该数的。也就满足二分的条件了。
code:
class Solution { public: int check(vector<vector<int>>& matrix, int mid,int n,int k){ int i=n-1; int j=0; int num=0; while(i>=0&&j<=n-1){ if(matrix[i][j]<=mid){ num+=i+1; j++; } else i--; } return num>=k;//num是比小于等于mid的元素的个数。 } int kthSmallest(vector<vector<int>>& matrix, int k) { long n=matrix.size(); long l=matrix[0][0]; long long r=matrix[n-1][n-1]; long long ans=l; while(l<=r){ long long mid=(l+r)/2; bool c=check(matrix,mid,n,k); if(c){//说明小于等于mid的元素个数比k多,answer<=mid r=mid-1; ans=mid; } else l=mid+1; } return ans; } };
有个问题。如果mid不在矩阵中怎么办?check函数返回值为1的时候,说明小于等于mid的元素比k多,那么answer<=mid,即让mid变小一点,check最后一次等于1时,answer一定等于mid。因为mid在小就不满足条件了。所以即便mid不再矩阵中出现,也可以找到答案。