力扣378

"""
378. 有序矩阵中第K小的元素
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。



示例:

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

返回 13。
"""

第一个我们很容易想到将二维数组展开成一维,然后直接进行排序,这里就不多再赘述

思路2,我们可以把此题看作是合并K个有序列表,而他在列上也满足升序排序,所以我们可以通过归并的思想来进行第K小元素查找

from typing import *
import heapq


class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        # 思路1 直接取成一维然后排序

        # 思路2 利用小根堆进行归并排序
        """
        因为矩阵每一行第一个元素,都是其当前行最小的元素
        所以我们把他存进小根堆里
        因为找第K小元素,实际上我们 按照升序,遍历到第K个即可

        我们存进小根堆的是一个三元组(元素值,第一维索引,第二维索引)
        每次先弹出栈顶元素,即最小的那个,如果第二维索引没到n-1,表示该行没遍历完
        因此读取下一个元素,并存进堆里

        如此反复K-1次(因为一开始存了算1次) 栈顶元素就是第K小元素

        :param matrix:
        :param k:
        :return:
        """
        n = len(matrix)
        pq = [(matrix[i][0], i, 0) for i in range(n)]
        heapq.heapify(pq)

        # print(pq)
        for i in range(k-1):
            # print(pq)
            num, x, y = heapq.heappop(pq)
            if y != n-1:
                heapq.heappush(pq, (matrix[x][y+1], x, y+1))

        return heapq.heappop(pq)[0]

另外我们可以采用二分法,观察到左上角和右下角分别是整个数组的上下界,我们可以通过二分去选取元素,再在这个元素里面,去统计是否是第k小

    def kthSmallest2(self, matrix: List[List[int]], k: int) -> int:
        """
        初始位置在 matrix[n - 1][0]matrix[n−1][0](即左下角);

        设当前位置为 matrix[i][j]matrix[i][j]。若 matrix[i][j]≤mid,

        则将当前所在列的不大于 mid 的数的数量(即 i + 1)累加到答案中,并向右移动,否则向上移动;

        不断移动直到走出格子为止。


        不妨假设答案为 xx,那么可以知道 l\leq x\leq rl≤x≤r,这样就确定了二分答案的上下界。

        每次对于「猜测」的答案 midmid,计算矩阵中有多少数不大于 midmid :

        如果数量不多于 kk,那么说明最终答案 x 不小于 midmid;
        如果数量少于 kk,那么说明最终答案 x 大于 midmid。

        :param matrix:
        :param k:
        :return:
        """

        n = len(matrix)

        def check(mid):
            i, j = n-1, 0
            num = 0
            # 这里取n-1是防止数组越界,
            while i >= 0 and j < n:
                if matrix[i][j] <= mid:
                    num += i + 1
                    j += 1
                else:
                    i -= 1
            return num >= k

        left, right = matrix[0][0], matrix[-1][-1]
        while left < right:
            mid = (left+right) // 2
            if check(mid):
                right = mid
            else:
                left = mid + 1

        return left
```![在这里插入图片描述](https://img-blog.csdnimg.cn/20200702110258299.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDEwNjkyOA==,size_16,color_FFFFFF,t_70)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值