剑指 day 10【JZ29 顺时针打印矩阵】奇思妙想之逆/顺时针旋转矩阵

在这里插入图片描述

解题思路

思路一:外循环打印圈数,内循环打印一圈

从左上角顶点为一圈的起点,打印完一圈后顶点变为右下角一个,外循环的条件是:i < raw/2 and i < col/2。打印一圈的函数实现较为复杂,要考虑各种情况,打印顺序为→↓←↑。因此,要编写合理的边界条件。同时应注意当某个方向已经无需打印时,后面的方向就无需打印了,因此应当及时结束掉。

  • 时间复杂度o(m*n),空间复杂度o(1)
class Solution:
    def printMatrix(self , matrix: List[List[int]]) -> List[int]:
        raw, col, i = len(matrix), len(matrix[0]), 0
        res = []
        def printCircle(matrix, start):
            i, j = start, start
            while i <= col - start - 1:		# →打印
                res.append(matrix[start][i])
                i += 1
            i, j = i-1, j+1		# →打印完后下面一个作为起点
            if j > raw - start - 1: return 
            while j <= raw - start - 1:		# ↓打印
                res.append(matrix[j][i])
                j += 1
            if i == start: return 
            i, j = i-1, j-1		# ↓打印完后左边一个作为起点
            while i >= start:		# ←打印
                res.append(matrix[j][i])
                i -= 1
            i, j = i+1, j-1		# ←打印完后上面一个作为起点
            while j > start:
                res.append(matrix[j][i])
                j -= 1

        while i < raw/2 and i < col/2:
            printCircle(matrix, i)
            i += 1
        return res

思路二:缩减四周边界

用 left, right, up, down存储边界,每次打印的范围都将由边界限定。一旦边界收缩到0,则代表已经遍历完,可以终止。

  • 时间复杂度o(m*n),空间复杂度o(1)
class Solution:
    def printMatrix(self , matrix: List[List[int]]) -> List[int]:
        row, col = len(matrix), len(matrix[0])
        left, right, up, down = 0, col-1, 0, row-1
        res = []
        while True:
            for i in range(left, right+1):
                res.append(matrix[up][i])
            up += 1
            if up > down: break
            for i in range(up, down+1):
                res.append(matrix[i][right])
            right -= 1
            if right < left: break
            for i in range(right, left-1, -1):
                res.append(matrix[down][i])
            down -= 1
            if down < up: break
            for i in range(down, up-1, -1):
                res.append(matrix[i][left])
            left += 1
            if left > right: break
        return res

思路三:用visit标记已走过位置,省去复杂的边界判断

类似于走迷宫一样,用visit数组标记走过的位置,这样每次下一步碰到已经走过的标记时就换方向。方向按照右下左上排布。

  • 时间复杂度:o(nm),空间复杂度o(nm)
class Solution:
    def printMatrix(self , matrix: List[List[int]]) -> List[int]:
        if matrix == [[]]: return []
        dxl, dyl = [0, 1, 0, -1], [1, 0, -1, 0]
        row, col = len(matrix), len(matrix[0])
        visit = [[0]*col for _ in range(row)]
        x, y, resStep = 0, 0, row*col-1
        visit[x][y], res, direct = 1, [matrix[0][0]], 0
        while resStep:
            dx, dy = dxl[direct%4], dyl[direct%4]
            while x+dx <= row-1 and y+dy <= col-1 and not visit[x+dx][y+dy]:
                x, y = x+dx, y+dy
                visit[x][y], resStep = 1, resStep-1
                res.append(matrix[x][y])
            direct += 1
        return res

思路四:奇思妙想-逆时针旋转矩阵,每次打印并删除一行

每剔除矩阵最上面一行数据,并添加到顺序列表;然后逆时针90°旋转剩下的矩阵,重复之前的剔除操作;这样直到矩阵为空,此时顺序列表的数字就是我们要找的 顺时针打印的数字!这种方法无需考虑复杂的打印边界条件!

  • 时间复杂度o(mn),空间复杂度o(mn)

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

class Solution:
    def printMatrix(self , matrix: List[List[int]]) -> List[int]:
        res = []
        while matrix:
            res.extend(matrix.pop(0))
            matrix = list(map(list, zip(*matrix)))[::-1]	# 注意:一定要加*解包,否则相当于没变
        return res

总结

  • 顺时针旋转矩阵:
matrix = list(map(list, zip(*matrix[::-1])))

在这里插入图片描述

  • 逆时针旋转矩阵:
matrix = list(map(list, zip(*matrix)))[::-1]

在这里插入图片描述

为什么要加*号?

*字符称为解包运算符。当它出现在可iterable对象后面时,它所做的就是将可iterable中的项逐个传递给函数的调用方,相当于把所有操作数都解压了一层。*二维数组------>数组中的每行的迭代

p = [[1,2,3],[4,5,6]]
>>>d=zip(p)
>>>list(d)
[([1, 2, 3],), ([4, 5, 6],)]

>>>d=zip(*p)
>>>list(d)
[(1, 4), (2, 5), (3, 6)]

可以看到如果不加*号,实际上输出的还是原始值。
因为*号是将列表(或其他iterable)解包,使其每个元素都成为单独的参数。
所以如果没有*号,你就是在做zip( [[1,2,3],[4,5,6]], ),zip后只有一个列表,他会进行迭代操作,把这个列表中的每一个迭代元素(即每一行)和元素为0的空列表进行打包。
使用*号时,数组中的每一行成为单独的元素,相当于使用zip([1,2,3], [4,5,6]),这样才会对数组中的每一个元素进行打包。
最后,由于打包后的是元组元素,因此我们使用map将其转化为list。
——————————————————————————————————————————
关于python:zip(list)和zip(* list)之间的区别
Python中的zip(), *zip()与zip(*zip(a,b))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值