378. Kth Smallest Element in a Sorted Matrix(python+cpp)

题目:

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.

解释:
首先,这个数组左上角的一定是最小值,右下角的一定是最大值
一.看到排序问题首先想到的就是用二分查找做,剑指offer上面的题目是在这样的二维数组中查找一个数字,如果这个数字存在的话,返回true,不存在则返回false。
对于这个数组,可以发现的一个规律是:对于右上角的数字,它左边的数字,都小于它,它下边的数字都大于它。
所以我们猜测某个值guess就是第k大的数,那么在数组中,我们需要找到比它小的数的个数,如果比它小的个数大于k个,那么就往前找,如果比它小的个数小于k个,那么就往后找(二分查找)。
对于一个数字,可以肯定的一点是它左边的数字都比它小,所以对于每个元素matrix[i][j],从右往左找到它这一行以及它下面所有行的第一个比它小的数,假设列号是[j]那么这一行比它小的数就是j+1个,最后每一元素的比它小的数都存在于它左边的一个左上角阶梯状的形状中。
不能直接用>0 <0 =0判断,因为==0的时候的guess值有可能不在matrix中,所以注意right的更新,以及最后返回的是left。注意while循环是<不然最后可能跳不出循环。
二.然后这道题还可以用堆做:
python中只有最小堆,如果想用最大堆,先对所有元素取负号,最后再取负号恢复
把有可能成为最小的元素的值往里面放,放入的个数大于k个。后期可能一次性pop()
1.第一种解法,可以把所有的元素都放进堆中,然后pop k次得到最终结果,但是效率很低,没有用到矩阵本身排序的性质。
2.第二种解法,利用到矩阵本身的性质,不需要把所有的元素都放进去,从左上角开始放(因为左上角的值全局最小),只需要把最可能是最小值的元素进堆即可,把最左上角的元素和其索引进堆,对k进行遍历,每次弹出最小的元素,把该元素右边的元素进堆,如果该元素是第一列的元素,则把它下面的元素也进堆。
第一种解法,二分查找:
python代码:

class Solution:
    def kthSmallest(self, matrix, k):
        """
        :type matrix: List[List[int]]
        :type k: int
        :rtype: int
        """
        n=len(matrix)
        def possible(guess):
            cnt=0
            r,c=0,n-1
            #对行遍历
            while(r<n):
                while(c>=0 and matrix[r][c]>guess):
                    c-=1
                cnt+=c+1;
                r+=1;
            return cnt>=k
        left=matrix[0][0]
        right=matrix[n-1][n-1]
        while (left<right):
            mid=left+(right-left)//2
            
            if possible(mid):
                right=mid
            else:
                left=mid+1
        return left

c++代码:

#include<vector>
using namespace std;
class Solution {
public:
    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(possible(matrix,mid,k))
            {
                right=mid;
            }
            else
            {
                left=mid+1;
            }
        }
        return left;
    }
    bool possible(vector<vector<int>>& matrix,int guess,int k)
    {
        int cnt=0;
        int n=matrix.size();
        int r=0,c=n-1;
        while(r<n)
        {
            while(c>=0 && matrix[r][c]>guess)
                c--;
            cnt+=c+1;
            r++;
        }
        return cnt>=k;
    }
};

利用堆的解法,python代码:

class Solution(object):
    def kthSmallest(self, matrix, k):
        """
        :type matrix: List[List[int]]
        :type k: int
        :rtype: int
        """
        if not matrix:
            return None
        m,n=len(matrix),len(matrix[0])
        nums=[(matrix[0][0],0,0)]
        heapq.heapify(nums)
        for _ in xrange(k):
            val,i,j=heapq.heappop(nums)
            if j==0 and i+1<m:
                heapq.heappush(nums,(matrix[i+1][j],i+1,j))
            if j+1<n:
                heapq.heappush(nums,(matrix[i][j+1],i,j+1))
        return val    

总结
我觉得这道题目的经典解法还是二分查找,而且二分查找的速度真的很快。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值