题目
给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
你必须找到一个内存复杂度优于 O(n2) 的解决方案。
示例 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
解题
方法一:直接排序
但是时间、空间复杂度不是最优
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]; } };
方法二:二分查找
对于一个数mid,比它小的可以分为左上部分,比它大的可以分为右下部分,根据mid值,可以求出左上角的元素数量,可以跟k去比较。因此根据这个思路,可以进行二分查找,直接找值。
但是可能会有疑惑,left就一定在矩阵中吗?
是可以保证一定在的。 check(mid)是false,说明左上角数量比较少,因此mid+1,值是每次+1,第一次出现num==k的时候,此时left就一定是出现在矩阵里的
class Solution { public: bool check(vector<vector<int>>& matrix,int mid,int k,int n){ int i=n-1,j=0; int num=0; while(i>=0&&j<n){ if(matrix[i][j]<=mid){ num+=i+1; j++; }else{ i--; } } return num>=k; } int kthSmallest(vector<vector<int>>& matrix, int k) { int n=matrix.size(); int left=matrix[0][0]; int right=matrix[n-1][n-1]; while(left<right){ int mid=left+(right-left)/2; if(check(matrix,mid,k,n)){ right=mid; }else{ left=mid+1; } } return left; } };