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

Posted qq_40707462

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode中等378有序矩阵中第 K 小的元素相关的知识,希望对你有一定的参考价值。

给你一个 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

思路1:优先队列

class Solution 
    public int kthSmallest(int[][] matrix, int k) 
        PriorityQueue<Integer>pq=new PriorityQueue<>((n1,n2)->(n2-n1));//大顶堆
        for(int[]a:matrix)
            for(int b:a)
                pq.offer(b);
                if(pq.size()>k) pq.poll();
            
        
        return pq.peek();
    

思路2:归并排序

类似 23、合并K个升序链表【困难】,合并 n 行
注意优先队列里要记录当前数的坐标

时间复杂度:O(klogn),归并 k 次,每次堆中插入和弹出的操作时间复杂度均为 logn。

空间复杂度:O(n),堆的大小始终为 n。

class Solution 
    public int kthSmallest(int[][] matrix, int k) 
        PriorityQueue<int[]>pq=new PriorityQueue<>
        	((int[]n1,int[]n2)->(n1[0]-n2[0]));//小顶堆
        int n=matrix.length;
        for(int i=0;i<n;i++) pq.offer(new int[]matrix[i][0],i,0);
        for(int i=0;i<k-1;i++)//弹出当前最小的一个,弹出k-1次
            int[]cur=pq.poll();
            if(cur[2]!=n-1)
                pq.offer(new int[]matrix[cur[1]][cur[2]+1],cur[1],cur[2]+1);
            
        
        
        return pq.poll()[0];
    

思路3:二分

整个二维数组中 matrix[0][0] 为最小值,matrix[n−1][n−1] 为最大值,将其分别记作 l 和 r。

任取一个数 mid 满足 l≤mid≤r,那么矩阵中不大于 mid 的数,肯定全部分布在矩阵的左上角。

例如下图,取 mid=8:

  • 初始位置在 matrix[n−1][0](即左下角);
  • 设当前位置为 matrix[i][j]。若 matrix[i][j]≤mid,则将当前所在列的不大于 mid 的数的数量(即 i+1)累加到答案中,并向右移动,否则向上移动;不断移动直到走出格子为止。
  • 每次对于「猜测」的答案 mid,计算矩阵中有多少数不大于 mid :
    如果数量不少于 k,那么说明最终答案 x 不大于 mid;
    如果数量少于 k,那么说明最终答案 x 大于 mid。

时间复杂度:O(nlog(r−l)),二分查找进行次数为O(log(r−l)),每次操作时间复杂度为 O(n)。
空间复杂度:O(1)

class Solution 
    public int kthSmallest(int[][] matrix, int k) 
        int n = matrix.length;
        int left = matrix[0][0];
        int right = matrix[n - 1][n - 1];
        while (left < right) 
            int mid = left + ((right - left) >> 1);
            if (check(matrix, mid, k, n)) 
                right = mid;
             else 
                left = mid + 1;
            
        
        return left;
    

    public boolean check(int[][] matrix, int mid, int k, int n) 
        int i = n - 1;
        int j = 0;
        int num = 0;
        while (i >= 0 && j < n) 
            if (matrix[i][j] <= mid) 
                num += i + 1;//这一列[0,i]共i+1个数
                j++;//右移
             else 
                i--;//上移
            
        
        return num >= k;
    

以上是关于leetcode中等378有序矩阵中第 K 小的元素的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

LeetCode 每日一题 378. 有序矩阵中第K小的元素

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

leetcode378 有序矩阵中第k小的元素