关注微信公众号“酸痛鱼”,获得更多最新最全的文章。

本文中所涉及的代码,在未特殊声明的情况下,都是基于Python3程序设计语言编写的。

建议您在PC浏览器中阅读本文,以获得更好的阅读体验。

如果您未掌握知识提要中的内容,建议您先掌握这些内容之后再阅读本文。

知识提要

0、列表乘法:list_obj * n

1、列表生成:[exp for v in seq_obj]

0

问题描述

实现一个函数,给定一个m x n的矩阵matrix,按照顺时针螺旋顺序遍历,返回遍历结果。要求不能改变matrix的内容。

例如:

给定 matrix = [[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

边长步进法

边长步进法

仔细观察示图,我们可以发现如下两个规律:

A、每次横向边走一次,下一次横向边的步进数减1;每次纵向走一次,下一次纵向边的步进数减1。

例如第一圈顶边的步进数为8,第一圈底边的步进数为7,第二圈顶边的步进数为6,第二圈底边的步进数为5。纵向边也有同样的规则,第一圈右边的步进数为5,第一圈左边的步进数为4,第二圈右边的步进数为3,第二圈左边的步进数为2。

B、顶边的步进方向为正,即1;右边的步进方向为正,即1;顶边的步进方向为负,即-1;左边的步进方向为负,即-1。

而且当横坐标步进不为0时,纵坐标步进为0;当纵坐标步进不为0时,横坐标步进为0。每4条边一个循环。所以我们可以用两个数组来表示每条边横坐标(列)和纵坐标(行)每一圈在四条边的步进方向。

# 列步进方向
# 顶,右,底,左
cds=[1, 0, -1, 0]# 行步进方向
# 顶,右,底,左
rds=[0, 1, 0, -1]

在代码实现中,拐弯的次数和正在遍历的边是有对应关系的。拐弯次数为0是正在遍历顶边;拐弯次数为1时正在遍历右边;拐弯次数为2时正在遍历底边;拐弯次数为3时正在遍历左边;拐弯次数为4时正在遍历顶边;依此循环,每4次拐弯一次交替。所以我们记录了拐弯的次数,就可以推算出正在遍历的边,自然也就可以得到当前行和列的步进方向。

def spiralOrder(matrix):if not matrix:return []cds = [1, 0, -1, 0] # 列坐标步进方向rds = [0, 1, 0, -1] # 行坐标步进方向# 行列当前元素数量(步进数)rs, cs = len(matrix), len(matrix[0])turns = 0 # 拐弯次数r, c = 0, -1 # 当前元素坐标elem_num = rs * csresult = [0] * elem_num # 结果index = 0 # 当前结果下标while index < elem_num:di = turns % 4 # 步进方向下标# 每次拐弯,交替使用行和列的步进steps = cs if turns % 2 == 0 else rsfor i in range(steps):r += rds[di]c += cds[di]result[index] = matrix[r][c]index += 1# 每两次拐弯,行列的步进数递减if turns % 2 == 0:cs -= 1rs -= 1turns += 1return result

事实上,列和行的步进方向cd和rd在每次拐弯中,是符合如下迭代规则的:

cd, rd = -rd, cd

这个规则是很容易推算的,这里我不作详细讲解,留给各位读者作为思考题。

另外,上边的代码实现进行了两次turns == 0 的判定,我们可以把它们合并成一个。基于这两个事实,我们可以把上边的代码实现优化成如下的样子。

def spiralOrder(matrix):if not matrix:return []cd, rd = 1, 0 # 列和行步进方向rs, cs = len(matrix), len(matrix[0])turns = 0r, c = 0, -1elem_num = rs * csresult = [0] * elem_numindex = 0while index < elem_num:if turns % 2 == 0:steps = cscs -= 1rs -= 1else:steps = rsfor i in range(steps):r += rdc += cdresult[index] = matrix[r][c]index += 1turns += 1# 每次拐弯,重新决定行列步进方向cd, rd = -rd, cdreturn result

2

边界标记法

我们可以用一个额外的矩阵来标记每一个元素是否已经被遍历。我们在遍历某一条边的时候,总是朝着一个固定的方向走,如果遇到了边界,或者发现下一个元素已经被遍历,那么就是该拐弯的时候了。示图给出了代码中visited矩阵的示例图,元素T表示已经被访问过,F表示未被访问。

visited矩阵

每次拐弯,行列方向的规则与“边长步进法”的一致。

def spiralOrder(matrix):if not matrix:return []cd, rd = 1, 0 # 列和行的步进方向rows, cols = len(matrix), len(matrix[0])# 用于记录每个元素的访问状态visited = [[False] * cols for _ in range(rows)]r, c = 0, 0elem_num = rows * colsresult = [0] * elem_numfor i in range(elem_num):result[i] = matrix[r][c]visited[r][c] = True# 下一步的坐标nr和nc# 如果不越界,或者未被访问,则下个坐标就是nr和nc# 否则拐弯nr, nc = r + rd, c + cdif 0 <= nr < rows and 0 <= nc < cols and not visited[nr][nc]:r, c = nr, ncelse:cd, rd = -rd, cd # 重算拐弯后的步进方向r, c = r + rd, c + cdreturn result

虽然这个方法比较容易理解和直观,但它需要额外的空间复杂度为O(mn),用于存储visited矩阵。


●微信 扫码关注,发家致富

矩阵横向输出_Python3算法之八:矩阵螺旋遍历相关推荐

  1. matlab中服从高斯分布的矩阵_推荐基础算法之矩阵分解PMF

    推荐基础算法之矩阵分解PMF 大多数存在的协同过滤算法不能处理以下两种情况: 1. 不能处理大规模数据 2.不能处理评分非常少的用户数据 概率矩阵分解模型可以解决大规模.稀疏且不平衡的数据.这篇文章主 ...

  2. 矩阵相乘的strassen算法_矩阵乘法的Strassen算法+动态规划算法(矩阵链相乘和硬币问题)...

    矩阵乘法的Strassen 这个算法就是在矩阵乘法中采用分治法,能够有效的提高算法的效率. 先来看看咱们在高等代数中学的普通矩阵的乘法 两个矩阵相乘 上边这种普通求解方法的复杂度为: O(n3) 也称 ...

  3. 矩阵相乘的strassen算法_4-2.矩阵乘法的Strassen算法详解

    题目描述 请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法. 思路分析 根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义.如A是m×n矩阵和B ...

  4. python矩阵旋转函数_Python3算法之十:矩阵旋转

    关注微信公众号"酸痛鱼",获得更多最新最全的文章. 本文中所涉及的代码,在未特殊声明的情况下,都是基于Python3程序设计语言编写的. 建议您在PC浏览器中阅读本文,以获得更好的 ...

  5. 将一个一维数组转化为二进制表示矩阵。例如_算法之矩阵最大区域问题

    例如:给定一个m*m(0<n)的矩阵,请找到此矩阵的一个子矩阵,并且此子矩阵的各个元素的和最大,输出这个最大的值.或者给出一个柱形矩阵求最大子矩阵的最大值. 首先我们需要了解一下最大字段和问题. ...

  6. c语言定义int 输出4386,C语言 · 矩阵乘法

    问题描述 输入两个矩阵,分别是m*s,s*n大小.输出两个矩阵相乘的结果. 输入格式 第一行,空格隔开的三个正整数m,s,n(均不超过200). 接下来m行,每行s个空格隔开的整数,表示矩阵A(i,j ...

  7. 矩阵连乘——动态规划算法

    矩阵连乘--动态规划算法 目录 矩阵连乘--动态规划算法 预备知识 前言 问题 应用动态规划方法的步骤 按照步骤分析问题 步骤1:最有括号化方案的结构特征 步骤2:一个递归求解方案 步骤3:计算最优代 ...

  8. 矩阵连乘问题算法思想_动态规划-矩阵连乘问题(一)

    动态规划的理论性和实践性都比较强,一方面需要理解状态.状态转移.最优子结构.重叠子问题等概念,另一方面又需要根据题目的条件灵活设计算法. 动态规划是一种用途很广的问题求解方法.它本身并不是一个特定的算 ...

  9. 基于项目的协同过滤推荐算法单机版代码实现(包含输出电影-用户评分矩阵模型、项目相似度、推荐结果、平均绝对误差MAE)

    基于项目的协同过滤推荐算法单机版代码实现(包含输出电影-用户评分矩阵模型.项目相似度.推荐结果.平均绝对误差MAE) 一.开发工具及使用技术 MyEclipse10.jdk1.7.movielens数 ...

最新文章

  1. Maven 常见问题
  2. 印度颁布法令:禁止Facebook免费网络服务
  3. Buuctf(pwn) picoctf_2018_rop chain 栈溢出
  4. 从字节码看 finally关键字、异常表
  5. 超出内容用省略号替代
  6. 做人真善美,做事拖后腿
  7. ansible 容器部署_如何使用Ansible Container管理Linux容器
  8. 人月神话-外科手术队伍:团队建设
  9. canvas - drawImage()方法绘制图片不显示的问题
  10. 基于3DMM的三维人脸重建技术总结
  11. 计算两个日期之间,相差多少天C语言详解
  12. java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener解决方案
  13. Linux Kernel Patched
  14. android 解决ScrollView中的子布局不能够填充整个ScrollView
  15. linux无损分区调整,linux如何无损调整分区大小
  16. 减法公式运算法则_小学所有的运算定律和什么叫加法什么叫减法,乘法a+b=c什么的公式也要...
  17. FC总线基础知识(2)——光纤交换机
  18. 胡凡算法笔记第二章摘录
  19. 2021年高考语文作文成绩查询,2021年国家高考语文作文题
  20. 阿德莱德计算机科学学士好吗,高考成绩不理想,终获澳洲阿德莱德大学计算机科学学士...

热门文章

  1. 主线程中慎用WaitForSingleObject (WaitForMultipleObjects)
  2. keepalived+lvs基于http检测
  3. 5G浪潮推动 射频产业风起云涌
  4. HTML5_Canvas_属性、定义及方法
  5. 对PostgreSQL中bgwriter的 MyProc 的理解
  6. 09hibernate_session_flush
  7. js跨域的理解与实现
  8. Windows 2000命令行如何查看进程PID和杀进程
  9. 华为机试HJ46:截取字符串
  10. 无法装载这个对象_面试官:别的我不管,这个JVM虚拟机内存模型你必须知道