每天更新一道python leetcode题,力求讲解清晰准确,客官们可以点赞或者关注。
给定一个包含 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]
思路:设置四种case,观察到第一种case是行不变列一直在变,第二种case的列数不变行数变,以此类推。
并且可以发现规律,第一次遍历的个数等于列数,第二次遍历的个数等于行数减一,第三次等于列数减一,第四次等于行数再减一。。。
算法过程:
解释代码中的参数作用
case表明是哪一种情况,0对应向右, 1对应向下,2 对应向左,3对应向上
ri, ci 表示我们当前遍历的点的位置坐标。
row, col, 用来代表这一次运动的步数。我们用它们可以组合出下一次终点的坐标。举例,若是case0向右运动,所以(ri, ci + col)就是运动末位置的后一项。注意到每次运动的步数都逐步减少,发现规律:当你移完横向运动类型的运动后,row -= 1;而竖的运动(case 1 3), col -= 1。然后每一次case结尾更新ri, ci也即此次运动的末尾坐标和下一次开始的起始坐标。
class Solution:
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
def cyc(row, column, ri, ci, case):
#递归终止条件
if row == 0 or column == 0:
return
#第一种case,横着走
if case == 0:
#结束的位置的column
endci = ci + column
for i in range(ci, endci):
#添加元素
re.append(matrix[ri][i])
#横移后row的长度减一
row -= 1
ri += 1
ci = endci-1
#我们想让case 不断增加但在0-4内循环
case = (case + 1)%4
cyc(row, column, ri, ci, case)
elif case == 1:
endri = ri + row
for i in range(ri, endri):
re.append(matrix[i][ci])
column -= 1
ci -= 1
ri = endri-1
case = (case+1)%4
cyc(row, column, ri, ci, case)
elif case == 2:
endci = ci - column
for i in range(ci, endci, -1):
re.append(matrix[ri][i])
row -= 1
ri = ri - 1
ci = endci + 1
case = (case+1)%4
cyc(row, column, ri, ci, case)
elif case == 3:
endri = ri - row
for i in range(ri, endri, -1):
re.append(matrix[i][ci])
column -= 1
ri = endri + 1
ci = ci + 1
case = (case+1)%4
cyc(row, column, ri, ci, case)
re = []
row = len(matrix)
if row == 0:
return []
column = len(matrix[0])
cyc(row, column, 0, 0, 0)
return re
算法证明:
这里面最难思考的就是row -= 1和 col -= 1,但这一点是可以自己验证的。
这里无法提供数学上的证明,只能归纳思考。
总结难点:
1)建模,抽象出四种运动,发现这四种运动的不同
2)为函数设置参数,记录每次要走的步数和起始的位置。
3)发现row, col即每次要走的步数与上一次走的方向的数学关系。