一天一大 leet(有序矩阵中第 K 小的元素)难度:中等-Day20200702
时间:2022-07-25
本文章向大家介绍一天一大 leet(有序矩阵中第 K 小的元素)难度:中等-Day20200702,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。
示例
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
提示
你可以假设 k 的值永远是有效的,1 ≤ k ≤ n2 。
抛砖引玉
暴力排序
- 首先想到的是先拼接数组
- 后排序直接取第 k-1 位(索引 0,第一小)
/**
* @param {number[][]} matrix
* @param {number} k
* @return {number}
*/
var kthSmallest = function (matrix, k) {
let sorted = []
for (let i = 0; i < matrix.length; i++) {
sorted = [...sorted,...matrix[i]]
}
sorted.sort((a, b) => a - b)
return sorted[k - 1]
}
题目中每行和每列元素均按升序排序这个应该可以作为优化的点
1 |
2 |
3 |
4 |
---|---|---|---|
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
31 |
32 |
33 |
34 |
随便找一个符合规则的matrix,找下规则(row表示行,i表示行索引,column,表示列j表示列索引)
- matrix[0][0]最小,matrix[row-1][column-1],最大
- 那么当指针在matrix[i][j],下一个比他大的数会出现的位置会在matrix[x][y]到matrix[row-1][column-1]
- x范围:i到row-1
- y范围:当x为i时(j到column-1),当x为i++(大于i)时,在0到j之间可能也会有下一个比他大的数
想要单次遍历逐个递增的来统计第k小的数,会发现下一个比他大的数的区值范围在一个梯形范围内很难具体定位, 换个思路,既然指定一个数,我可以定位到大于他的范围,那假设我已经知道了第k小的元素是m那么,直接统计小于他的数是不是k-1个就可以验证m的真实性了。
二分法
- matrix[0][0]到matrix[row-1][column-1]中任意取一个数mid做第k小的数,(取中间值,会最快取到想要的值)
- 遍历matrix检查小于mid的数是否等于k
- 大于k,则说明m取大了,那么再从matrix[0][0]到m中取个中间值
- 小于k,则说明m取小了,那么再从m到matrix[row-1][column-1]中取个中间值
- 等于k,理论上是取到看第k个,但是因为取的是中间值,也许这个数并不在matrix,那么只能再进行范围划分知道上下线重合
var kthSmallest = function (matrix, k) {
let n = matrix.length;
let left = matrix[0][0];
let right = matrix[n - 1][n - 1];
while (left < right) {
let mid = left + parseInt((right - left) / 2, 10);
if (check(matrix, mid, k, n)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
function check(matrix, mid, k, n) {
let i = n - 1;
let j = 0;
let num = 0;
while (i >= 0 && j < n) {
if (matrix[i][j] <= mid) {
num += i + 1;
j++;
} else {
i--;
}
}
return num >= k;
}
}
其他解法
- 一行一行合并
- 之后合并的行循环按顺序插入到上一次合并的数组中
- 利用reduce第一个参数做合并的目标数组,异常逐行合并到其中
reduce方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
var kthSmallest = function(matrix, k) {
if(matrix.length < 1) return 0
let arr = matrix.reduce((a, b) => merge(a, b))
return arr[k - 1]
};
function merge(left, right){
let llen = left.length
let rlen = right.length
let i = 0
let j = 0
let res = []
// 后入数组先按大小入目标数组
while(i < llen && j < rlen){
if (left[i] < right[j]) {
res.push(left[i++])
} else {
res.push(right[j++])
}
}
// 排序逻辑中未入目标数组的子集依次进入
while(i < llen) res.push(left[i++])
while(j < rlen) res.push(right[j++])
return res
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- RTSP协议视频流媒体播放器EasyPlayer-RTSP-OCX接口文档API接口函数定义
- Python逐行写入
- C++ this 指针
- C++ push方法与push_back方法
- 别人变强靠天赋,而我,靠思维导图
- Spring Boot 五种热部署方式
- 二叉树最小深度
- 一日一技:限定Python函数只能被特定函数调用
- 四种ABAP单元测试隔离(test isolation)技术
- Python使用对象方式获取字典的值
- Hive整合HBase实现数据同步
- [数据结构与算法] 盘点工作中常用的算法
- MyBatis_resultMap 的关联方式实现多表查询(多对一)
- MyBatis_resultMap的N+1方式实现多表查询(多对 一)
- LeetCode 63. 不同路径 II