Leetcode378: Kth Smallest Element in a Sorted Matrix

378. Kth Smallest Element in a Sorted Matrix

   

Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.

Note that it is the kth smallest element in the sorted order, not the kth distinct element.

Example:

matrix = [
   [ 1,  5,  9],
   [10, 11, 13],
   [12, 13, 15]
],
k = 8,

return 13.

Note: 
You may assume k is always valid, 1 ≤ k ≤ n2.

题意:

给出一个矩阵,其中每一行每一列都是递增的,求出这个矩阵中第K小的数。

解答①:

暴力求解,对矩阵中的所有元素进行排序,输出排序后得到的数组的第k-1项即可。

代码:[cpp] view plain

  1. class Solution {  
  2. public:  
  3.     int kthSmallest(vector<vector<int>>& matrix, int k) {  
  4.     int n=matrix[0].size() ;//记下n   
  5.     vector<int> a;  
  6.     for(int i=0;i<n;i++){  
  7.         for(int j=0;j<n;j++)  
  8.         a.push_back(matrix[i][j]);  
  9.      }  
  10.     sort(a.begin(),a.end());  
  11.     return a[k-1];  
  12.     }  
  13. };  

复杂度:

因为矩阵中有n^2个元素,所以遍历矩阵中的元素的时间复杂度是O(n^2),对得到的数组进行排序的时间复杂度是O(n^2 * logn^2)=O(n^2 * logn)。所以暴力求解这个问题的时间复杂度是O(n^2 * logn)。

解法②:

上述解法的时间复杂度之所以很大,是因为在上面的情况中并没有充分第利用到题目给的每一行每一列递增的条件。为了解决这个问题,我自己在纸上面演算了一下如何手工求解这个问题。






所以对于求解上述矩阵中第k小的元素是什么,我会从左上角的这个最小的元素开始进行计数,再根据图中的步骤来寻找下一个最小的元素。下面的代码就是模拟上图的步骤来解决这个问题。

代码:[cpp] view plain

  1. class Solution {  
  2. public:  
  3.     int kthSmallest(vector<vector<int>>& matrix, int k) {  
  4.     int n=matrix[0].size() ;//记下n   
  5. int a[n]={0} ;//记用一个数组记录各列将要被访问的元素的位置  
  6. a[0]=1;  
  7.   
  8. int res=matrix[0][0] ;//起始点设为左上角的元素  
  9. int min=99999999;//初始化寻找的最小值变量  
  10.   
  11. int a1=0,a2=0;//辅助的两个变量  
  12.   
  13. for (int i=2;i<=k;i++) { //外循环控制的是寻找第K大的元素  
  14. for (int j=0;j<n;j++) {//内循环控制的是寻找按序排列中的下一个元素  
  15. if(a[j]<n && matrix[a[j]][j]<min){//找寻每一列未被访问到的元素中最小的元素  
  16. if(a1==0) a1=1;  
  17. else a[a2]--;  
  18. a2=j;  
  19. min = matrix[a[j]][j];   
  20. a[j]++;  
  21. }  
  22. }  
  23.    a1=0;  
  24.    res=min;  
  25.    min=99999999;  
  26.   
  27. }  
  28.    return res;  
  29.    
  30.     }  
  31. };  
复杂度:

通过这一种算法,每一次寻找下一个小的元素的时候,最坏情况下是需要遍历k列的,所以时间复杂度是O(kn)。又因为k是可以达到n^2的, 所以最坏情况下这个算法的时间复杂度是O(n^3)。

其实这个算法有一个问题,就是每一次寻找下一个小的元素的时候,是没有必要进行遍历每一个元素的,因为原先的矩阵具有每一行每一列递增的性质。我尝试着对上面的算法进行改进,但是始终有BUG的存在,边界情况考虑实现地不是很好。所以没有列出新的解。

由于上面两种解法都具有较高的时间复杂度,所以我有去搜索看看该题有没有比较简洁的做法。

解法③:

使用一个最大堆,然后遍历这个矩阵,将其加入堆。根据最大堆的性质,大的元素会排到最前面。然后判断当前堆中的元素有没有大于K个,要是大于K个的话,就将首元素删掉。循环结束后,堆中的首元素就是第K小的元素。[cpp] view plain

  1. class Solution {  
  2. public:  
  3.     int kthSmallest(vector<vector<int>>& matrix, int k) {  
  4.         priority_queue<int, vector<int>> q;  
  5.         for (int i = 0; i < matrix.size(); ++i) {  
  6.             for (int j = 0; j < matrix[i].size(); ++j) {  
  7.                 q.emplace(matrix[i][j]);  
  8.                 if (q.size() > k) q.pop();  
  9.             }  
  10.         }  
  11.         return q.top();  
  12.     }  
  13. };  

复杂度:

将矩阵中的元素遍历了一遍,因为矩阵中有n^2个元素,所以时间复杂度O(n^2)。从堆里面删除一个元素的复杂度为O(logn)。所以总的时间复杂度为O(n^2)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值