【矩阵二分】力扣378. 有序矩阵中第 K 小的元素

ops/2025/2/2 2:05:02/

给你一个 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
在这里插入图片描述

二分

class Solution {
public:bool check(vector<vector<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;j++;}else{i--;}}return k <= num;}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) >> 1;if(check(matrix, mid, k, n)){right = mid;}else{left = mid + 1;}}return left;}
};

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

在这里插入图片描述

矩阵中最小的元素是matrix[0][0],最大的元素是matrix[n-1][n-1],这道题使用二分查找的思想就是我们从最小数到最大数之间任意挑一个数字作为mid。假设mid = 8,根据图片,矩阵可以分成两个部分,一个部分全部小于等于8,另外一个部分全部大于8。我们可以统计左上部分小于等于8的数的数量,看8在排序后是第几小的数(因为图片有多个8,所以返回的是8是第几小的数的最大情况,即升序排列中最右边的8的位置)。

所以在二分查找中,我们从取left + right除以2的值为mid,如果在check函数中得出来左上部分的数量大于等于我们所期待的k,那么就说明我们的取的mid大于等于实际元素,这时候我们就将right = mid,缩小他的上界。如果左上部分数量小于我们所期待的k,说明我们取的mid比实际元素要小,我们令left = mid + 1,增加他的下界。

很多人会疑问left怎么确保一定是矩阵中的数?

如题解中所说,如果 num >= k,那么说明最终答案 x <= mid;如果 num < k,那么说明最终答案 x > mid。 在最后一次迭代时,check返回的结果为false,即 num < k,说明 x > mid,又因为 x <= right。当 left = mid + 1 后,left >= righ,while循环结束。此时有 mid < x <= right <= left = mid + 1,即 mid < x <= mid + 1。可得 x = mid + 1 = left。


http://www.ppmy.cn/ops/154908.html

相关文章

使用PyTorch实现逻辑回归:从训练到模型保存与加载

1. 引入必要的库 首先&#xff0c;需要引入必要的库。PyTorch用于构建和训练模型&#xff0c;pandas和numpy用于数据处理&#xff0c;matplotlib用于结果的可视化。 import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoade…

CSS关系选择器详解

CSS关系选择器详解 学习前提什么是关系选择器&#xff1f;后代选择器&#xff08;Descendant Combinator&#xff09;语法示例注意事项 子代选择器&#xff08;Child Combinator&#xff09;语法示例注意事项 邻接兄弟选择器&#xff08;Adjacent Sibling Combinator&#xff0…

双指针c++

双指针&#xff08;Two Pointers&#xff09;是一种常用的算法技巧&#xff0c;通常用于解决数组或链表中的问题&#xff0c;如滑动窗口、区间合并、有序数组的两数之和等。双指针的核心思想是通过两个指针的移动来优化时间复杂度&#xff0c;通常可以将 (O(n^2)) 的暴力解法优…

Titans 架构下MAC变体的探究

目前业界流行的 Transformer 模型架构虽然在大多数场景表现优秀&#xff0c;但其上下文窗口&#xff08;Window&#xff09;长度的限制&#xff0c;通常仅为几千到几万个 Token&#xff0c;这使得它们在处理长文本、多轮对话或需要大规模上下文记忆的任务中&#xff0c;往往无法…

flume和kafka整合 flume和kafka为什么一起用?

‌Flume和Kafka一起使用的主要原因是为了实现高效、可靠的数据采集和实时处理。‌‌12 实时流式日志处理的需求 Flume和Kafka结合使用的主要目的是为了完成实时流式的日志处理。Flume负责数据的采集和传输,而Kafka则作为消息缓存队列,能够有效地缓冲数据,防止数据堆积或丢…

Vue.js组件开发-实现导出PDF文件可自定义添加水印及水印样式方向

使用 Vue 实现导出 PDF 文件并添加水印&#xff0c;同时支持设置水印样式、方向和自定义水印内容。 步骤 安装依赖&#xff1a;使用 html2canvas 将 HTML 内容转换为 canvas&#xff0c;使用 jspdf 生成 PDF 文件。创建 Vue 组件&#xff1a;在组件中实现水印生成、HTML 转 c…

一文介绍Hive数据类型

一文介绍Hive数据类型 文章目录 一文介绍Hive数据类型写在前面基本数据类型集合数据类型介绍案例实操 类型转化隐式类型转换CAST操作 写在前面 Linux版本&#xff1a;CentOS7.5Hive版本&#xff1a;Hive-3.1.2 基本数据类型 如下表所示&#xff1a; Hive数据类型Java数据类型…

重构字符串(767)

767. 重构字符串 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a; class Solution { public:string reorganizeString(string s){string res;//因为1 < s.length < 500 &#xff0c; uint64_t 类型足够uint16_t n s.size();if (n 0) {return res;}unordere…