c++ 二维数组_leetcode之旅(二):数组(2)

小锅炒的数据结构与算法学习系列之leetcode之旅,本节主要介绍二维数组。

1. 二维数组

二维数组是一种结构较为特殊的数组,其数组的每个元素都是数组,即“数组的数组”。二维数组本质上仍然是一个一维数组。二维数组又称为矩阵,行列数相等的矩阵称为方阵。类似一维数组,计算机会在内存中申请申请一段连续 的空间来存储二维数组。

在实际中,通常使用二维数据处理矩阵类相关问题,包括矩阵旋转对角线遍历,以及对子矩阵的操作等。对于数据科学而言,对二维数组甚至多维数组的处理更是重中之重。其中Matlab和众多的python科学计算库(numpy、pandas等)都对二维数组(或高维数组)的处理提供了最大的便利。

256c3414e15f31b303a9008c7e65a958.png

2. 例题实战

867. 转置矩阵[简单] 

说明:

给定一个矩阵 A, 返回 A 的转置矩阵。

矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。

示例1:

输入: [[1,2,3],[4,5,6],[7,8,9]]
输出: [[1,4,7],[2,5,8],[3,6,9]]

示例2:

输入:[[1,2,3],[4,5,6]]
输出:[[1,4],[2,5],[3,6]]

解答:

1.按照题意,构造转置矩阵赋值即可 

2.使用内置函数zip

# 1.直接赋值
class Solution:
    def transpose(self, A: List[List[int]]) -> List[List[int]]:
        m, n = len(A), len(A[0])
        trans = [[0]*m for i in range(n)]
        
        for i in range(m):
            for j in range(n):
                trans[j][i] = A[i][j]
        
        return trans
# 2.内置函数
class Solution:
    def transpose(self, A: List[List[int]]) -> List[List[int]]:

        return [list(arr) for arr in zip(*A)]

注释:

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

# zip 方法在 Python 2 和 Python 3 中的不同:
#在 Python 2.x zip() 返回的是一个列表,Python3.x 返回对象
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
d = zip(a,b,c)
d, list(d)
(, [(1, 4, 7), (2, 5, 8), (3, 6, 9)])
# *zip() 解压
a, b, c = list(zip(*zip(a,b,c)))
a, b, c
((1, 2, 3), (4, 5, 6), (7, 8, 9))

867. 零矩阵[中等] 说明:

编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。

示例1:

输入:[[1,1,1],
       [1,0,1],
       [1,1,1]]
输出:[[1,0,1],
       [0,0,0],
       [1,0,1]]

解答:

  1. 按照题意,找到零元素,标记下标索引,分别将行列索引存储在两个列表里。要注意的的是in-place要求在原数组上改动。时间复杂度O(mn)
class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        row, col = [], []
        if not matrix:
            return None

        m, n = len(matrix), len(matrix[0])
        for i in range(m):
            for j in range(n):
                if matrix[i][j] == 0:
                    row.append(i)
                    col.append(j)
        
        # elimate the same index
        row = set(row)
        col = set(col)

        # process row
        for i in row:
            for j in range(n):
                matrix[i][j] = 0
        
        # process col
        for j in col:
            for i in range(m):
                matrix[i][j] = 0

498. 对角线遍历[中等] 

说明:

给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。

示例:

输入:[[ 1, 2, 3 ],
      [ 4, 5, 6 ],
      [ 7, 8, 9 ]]
输出: [1,2,4,7,5,3,6,8,9]

解答1:

  1. 遍历每个对角线的元素,外循环对角线最大的长度。每条对角线的下标索引和相等。难点在于索引的判断,防止下标越界。最后按照奇偶逆序连接即可。
class Solution:
   def findDiagonalOrder(self, matrix: List[List[int]]) -> List[int]:
       if not matrix:
           return []

       M, N = len(matrix), len(matrix[0])
       res, tmp = [], []
       for i in range(M+N-1):
           tmp.clear()
           # key import, not suquare matrix ,the location of element index
           r, c = 0 if i -1
  else i-N+ 1, i  if i -1  else N -1 while r and c >  -1:
               tmp.append(matrix[r][c])
               r +=  1
               c -=  1 if i %  2 ==  0:
               res.extend(tmp[:: -1]) else:
               res.extend(tmp) return res

注释:

下标索引的确定,如下图。当行小于列(M>N)时行以下标r=0开始,以行数截止;当行大于列时,循环次数大于列数即i>N-1,行数以下标r=i-N+1开始,,同理可以分析列的索引变化

acb4f1a8843a36ae605a3633b27b2f33.png

解答2:模拟法

类似矩阵迷宫模拟两种规则,往右上方 i -= 1, j += 1; 往左下方 i += 1,j -= 1 数组边界判断:

  • 往右上方 1 触碰上边界,未触碰右边界j += 1, i = i 2 触碰右边界,i += 1, j = j
  • 往左下方 1 触碰左边界,未触碰右边界i += 1, j = j 2 触碰下边界,j += 1 , i = i
class Solution:
    def findDiagonalOrder(self, matrix):
        if not matrix or not matrix[0]:
            return []
        M, N = len(matrix), len(matrix[0])
        matrix_num = M * N
        count = 0
       i, j = 0, 0
       result = []
       direction = "up"
       while (count             count += 1
            result.append(matrix[i][j])
            # 向右上方向走
            if direction == "up":
             # 无需调换方向的条件(1.i>0 碰到上边界前, 2jif i > 0 and j 1:
                     i -= 1
                     j += 1
                     continue
                else:
                     direction = "down"
                     # 碰到上边界:1 --> 2
                     if i == 0 and j 1
:
                         j +=  1 # 碰到右边界:3 --> 6 elif j == N -  1:
                         i +=  1             # 向左下方向走 else: # 无需调换方向的条件(1.i  0 碰到右边界前) if i 1  and y >  0:
                    i +=  1
                    j -=  1 continue else:
                    direction =  "up" # 碰左边界:4 --> 7 if  j ==  0  and x 1:
                         i +=  1 # 碰下边界:8 --> 9 elif i == M -  1 :
                         y +=  1         return result

参考链接:

1 https://leetcode-cn.com/leetbook/read/array-and-string/cuxq3/ 

2 https://leetcode-cn.com/problems/diagonal-traverse/solution/dui-jiao-xian-bian-li-by-leetcode/ 3  https://leetcode-cn.com/problems/diagonal-traverse/solution/zui-zhi-bai-de-xie - END -

编辑:flybird7

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值