当前位置: 首页 > news >正文

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
示例 2:

输入:matrix = [[-5]], k = 1
输出:-5

提示:

n == matrix.length
n == matrix[i].length
1 <= n <= 300
-109 <= matrix[i][j] <= 109
题目数据 保证 matrix 中的所有行和列都按 非递减顺序 排列
1 <= k <= n2

题解

有序 + 确定范围 可以使用二分查找

  1. 左上角matrix[0][0]是下限,右下角matrix[n-1][n-1]是上限,就有了一个值,第 k 小的元素在这个值域中
    我们对值域进行二分查找(mid=(matrix[0][0]+matrix[n-1][n-1])/2),使得mid逼近值域中的目标值(第 k 小的元素)
  2. 求出矩阵里小于等于mid的有几个,num个
  3. num 和 k 比较
    如果比 k 小,说明中间值小了,调整值域范围(left=mid+1)
    否则,说明中间值大了,调整值域范围(right=mid),一步步锁定目标值

注:

1. 为什么对值二分而不是对索引二分

二分查找可以根据索引二分,也可以根据数值二分,有序数组中,索引的大小可以反映值的大小,对索引二分就行
但这里不是有序的一维数组,索引不能体现值谁大谁小,无法通过二分索引逼近目标值

2. 为什么最后left是第k小的数||二分法如何保证最后的left or right 是数组中的元素?

因为每次值域收缩都保证了第 k 小的数在 left ~ right 之间,当 left==right 时,第 k 小的数即被找出,等于left

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int n = matrix.length;
        //left和right是矩阵值不是矩阵下标
        int left = matrix[0][0];
        int right = matrix[n - 1][n - 1];

       //一步步收缩值域范围直至left==right
       //因为每次值域收缩都保证了第 k 小的数在 left ~ right 之间,当 left==right 时,第 k 小的数即被找出,等于left
        while (left < right) {
            //避免溢出
            int mid = left + (right - left)/2;
            //满足 num >= k,范围太大,移动right至mid, 范围收缩
            //注意num=k时说明小于等于mid数的数量等于k,但不代表mid就是结果,因为此时mid不一定在matrix中
            if (check(matrix, mid, k, n)) {
                right = mid;
            } else {//满足 num < k,范围太小,移动left至mid+1, 范围收缩
                left = mid + 1;
            }
        }
        //跳出循环时left=right,返回值left是什么???
        return left;
    }

    //从矩阵左下角开始按列遍历每一列,计算每一列中比mid小的元素个数并累加获得num,将num与k比较
    //返回值boolean:矩阵中小于mid的数>=k
    //为什么不直接返回num=k时的mid值?因为mid是通过值域二分法计算出的值,不是实际的矩阵值
    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) {
                //当前元素小于mid,则本列此元素及上方元素均小于mid,num+=i+1(行号是i,行的数目是i+1)
                num += i + 1;
                //列向右移动,计算下一列小于mid的元素的个数
                j++;
            } else {
                //当前元素大于mid,则向上移动,直到找到比mid小的值,或者出矩阵
                i--;
            }

        }
        return num>=k;
    }

}

相关文章:

  • Linux安装Redis、远程连接Redis
  • Python使用SFTP批量上传和下载一个目录下的所有文件
  • flink tranform算子详解
  • 从厨电模范到数字先锋,看永洪科技如何助力方太集团开启数字新征程
  • 写一个python程序,找出1000以内的质数
  • c++ 接口/多态
  • 【开源免费】基于SpringBoot+Vue.JS疫情管理系统(JAVA毕业设计)
  • Java Web 相关技术概念与知识点
  • [MySQL初阶]MySQL(2)数据类型精讲静态类型和动态类型的对比
  • ubuntu20系统下conda虚拟环境下安装文件存储位置
  • 大模型在呼吸衰竭预测及围手术期方案制定中的应用研究
  • JVM如何判断一个对象可以被回收
  • 自定义wordpress三级导航菜单代码
  • 摄相机标定的基本原理
  • 15天 — 如何解决 Redis 中的热点 key 问题?Redis 集群的实现原理是什么?Redis 中的 Big Key 问题是什么?如何解决?
  • sqli-lab靶场学习(七)——Less23-25(关键字被过滤、二次注入)
  • 1.RabbitMQ简介
  • rust笔记13:trait对象
  • 电脑技巧:硬件检测工具 HWiNFO 8.16版本更新功能介绍
  • 点云滤波方法:特点、作用及使用场景
  • 哪些是用vue做的网站/重庆网站搜索引擎seo
  • 找企业名录的网站/seo外链收录
  • 制作网页怎样添加背景音乐/优化seo公司哪家好
  • 建设网站内容的策划书/seo外链收录
  • xly000.wordpress.com/seo营销推广公司
  • 个人主页自助建站/seo排名工具有哪些