JS版数据结构第四篇(矩阵)
栏目: JavaScript · 发布时间: 5年前
内容简介:本篇博客参考银国徽老师的《Javascript版数据结构与算法》其实从严格意义上来讲矩阵不能算一种典型的数据结构而之所以把矩阵放到这个系列里面是因为矩阵在面试和笔试中是非常高频出现的
本篇博客参考银国徽老师的《Javascript版数据结构与算法》
背景
其实从严格意义上来讲矩阵不能算一种典型的数据结构
而之所以把矩阵放到这个系列里面是因为矩阵在面试和笔试中是非常高频出现的
今天我们将会用js实现两道LeetCode上两道比较经典的矩阵相关的算法题
矩阵的定义对于大学学习过《线性代数》这门课程的同学们来讲应该都不会很陌生,如果有同学不了解可以自行查下百度百科。
不多废话,我们直接看题。
螺旋矩阵
LeetCode第54题原题地址
题目难度: 中等
题目描述:
给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
示例1:
输入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 输出: [1,2,3,6,9,8,7,4,5]复制代码
示例2:
输入: [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出: [1,2,3,4,8,12,11,10,9,5,6,7]复制代码
题目理解:
题目要求的是我们按照顺时针的顺序从外向内遍历每一个元素,并将他们按顺序返回出来。
根据这张图我们应该很清除的理解题目的要求了,题目要求的元素的返回顺序就是图中的1到16
思路分析:
我们可以注意到:
无论是几×几的矩阵,都是需要我们先将外圈遍历完成后才进入到它相邻内圈元素的遍历
如上图中我们将1-12看作第一圈,将13-16看作第二圈,第一圈全部遍历完成后才会遍历第二圈
如果有阶数更高的矩阵(更多圈数),还会有第三圈,第四圈的遍历
所以我们可以把每一圈的遍历视为一个步骤,不断地重复这个步骤就会得到我们需要的结果
相信有一些同学已经猜出我们要用递归解决这道题目了
接下来我们看一下代码具体是怎样实现的
代码实现
arr => { // map函数用来完成当前矩阵最外一圈的遍历 // @param1{Array}二维数组 arr 表示当前矩阵 // @param2{Array}一维数组 result 用来保存遍历结果 let map = (arr, result) => { // 矩阵的高度即行数 let n = arr.length // 遍历矩阵的每一行 for(let i = 0; i < n; i++){ // 若第一行 按顺序插入 if(i === 0){ result = result.concat(arr[i]) } else if (i === n-1){ // 若最后一行 倒序插入 result = result.concat(arr[i].reverse()) } else { // 若中间行 插入该行最后一个元素 并将该元素从矩阵中删除 result.push(arr[i].pop()) } } // 将已经遍历的第一行和最后一行从矩阵中删除 arr.pop() arr.shift() // 遍历插入最左侧一列 此时删除首位两行后矩阵高度已变为n-2 for(let j = n - 3; j >= 0; j--){ // 避免arr[j]长度为空时插入undefined if(arr[j].length){ result.push(arr[j].shift()) } } // 截止条件 矩阵有元素就继续递归 if(arr.length){ // 把已将遍历元素删除的矩阵进行递归 return map(arr, result) }else{ return result } } // 将初始矩阵传入, 保存结果的数组初始为空 return map(arr, []) }复制代码
思考
可能有些同学不太清除我们是怎样想到通过递归解决这样的问题。
这里根据个人的一些经验 我总结了一下满足递归的三个通用条件:
- 可以将一个操作拆解为处理过程相同的小步骤
- 每次步骤的输入数据格式都相同
- 运行次数未知
在这个题目中
- 首先我们将顺时针螺旋遍历拆解为每一圈的遍历
- 我们最开始接收一个二维数组(矩阵),每次遍历完成一圈后传入删除最外圈元素的新矩阵,它同样是一个二维数组
- 递归直到矩阵为空(传入的矩阵宽高并不确定)
符合了递归的三个条件。
大家今后碰到类似的题目就可以参照这三点来判断是否可以使用递归。
旋转图像
LeetCode第48题原题地址
题目难度:中等
题目描述
给定一个 n × n 的二维矩阵表示一个图像。 将图像顺时针旋转 90 度。
说明: 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。
请不要使用另一个矩阵来旋转图像。
示例1:
给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
示例2:
给定 matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
]
原地旋转输入矩阵,使其变为:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]
题目理解
题目很好理解,直接将矩阵顺时针旋转,有点类似于我们平时使用的将图片顺时针旋转90度的功能
而这个题目之所以叫做'旋转图像'也正是因为这道题目的实现方法就是图片旋转功能的原理。
思路分析
表面上看这道题很简单,我们只需要建立一个新的矩阵(二维数组),然后遍历原矩阵matrix的每一
列,按照从下到上的顺序添加至新矩阵的每一行中即可。
但是这道题的难度就在于题目中要求我们“原地旋转图像”,这意味着我们不可以新建一个二维数
组(矩阵),然后向里面添加数据,我们只能处理原矩阵,那处理原矩阵的话我们除了将数字交换位置
以外并没有其他的方法了。
那具体怎样交换呢?
以示例1为例,首先我们以中间行为轴,将矩阵进行轴对称
然后我们再以对角线753作为轴进行轴对称
此时就得到了我们想要的结果,接下来我们用代码实现它
代码实现
arr => { // 获取矩阵阶数 let n = arr.length let temp // 垂直翻转 考虑n的奇偶 for(let i = 0; i < Math.floor(n / 2); i++){ for(let j = 0; j< n; j++){ temp = arr[i][j] arr[i][j] = arr[n -1 -i][j] arr[n -1 -i][j] = temp } } // 沿对角线反转 for(let p = 0;p < n - 1; p++){ for(let q = p + 1; q < n; q++){ temp = arr[p][q] arr[p][q] = arr[q][p] arr[q][p] = temp } } return arr }复制代码
总结
LeetCode上面也有很多有关矩阵的题目,大家都可以去尝试着做一下,如果对我的方法有疑问也欢迎大家来评论区探讨,多交流才会有所进步,希望你早日成为大牛。
以上所述就是小编给大家介绍的《JS版数据结构第四篇(矩阵)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 机器学习 | SVD矩阵分解算法,对矩阵做拆分,然后呢?
- golang 算法-矩阵
- 彻底理解矩阵乘法
- [开源项目]矩阵数据的意义
- iphone – :CGAffineTransformInvert:奇异矩阵
- golang顺时针打印矩阵
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Docker——容器与容器云(第2版)
浙江大学SEL实验室 / 人民邮电出版社 / 2016-10 / 89.00元
本书根据Docker 1.10版和Kubernetes 1.2版对第1版进行了全面更新,从实践者的角度出发,以Docker和Kubernetes为重点,沿着“基本用法介绍”到“核心原理解读”到“高级实践技巧”的思路,一本书讲透当前主流的容器和容器云技术,有助于读者在实际场景中利用Docker容器和容器云解决问题并启发新的思考。全书包括两部分,第一部分深入解读Docker容器技术,包括Docker架......一起来看看 《Docker——容器与容器云(第2版)》 这本书的介绍吧!