378. 有序矩阵中第K小的元素

题目链接

题解:

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不再矩阵中出现,也可以找到答案。

原文地址:https://www.cnblogs.com/Accepting/p/13306146.html