[学习报告]《LeetCode零基础指南》(第七讲) 二维数组

一,二维数组简介

  二维数组相对于一维数组来说多了一个维度,如我们创建了一个二维数组 a r r [ r o w ] [ c o l ] arr[row][col] arr[row][col]。其中 r o w row row表示二维数组的行数,在每一行上有 c o l col col个元素。接下来要注意的是二维数组的在物理结构上可以把他理解为矩阵,但是在内存存储上,二维数组的存储是连续的也就是说当我使用行坐标 a r r [ 0 ] arr[0] arr[0]++时,得到的并不是 a r r [ 0 ] [ 1 ] arr[0][1] arr[0][1]而是 a r r [ 1 ] arr[1] arr[1],其次二维数组的数组名表示的是 a r r arr arr的首元素地址即是 a r r [ 0 ] arr[0] arr[0]而不是 a r r [ 0 ] [ 0 ] arr[0][0] arr[0][0]
  对二维数组的遍历通过简单的两重循环即可,同时对二维数组的理解除了矩阵之外还可以讲其中的每个维度看作二维DP的某个标准。

二,做题记录

1.1351. 统计有序矩阵中的负数

原题链接

给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 请你统计并返回 grid 中 负数 的数目。
示例 1:
输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
输出:8
解释:矩阵中共有 8 个负数。
示例 2:
输入:grid = [[3,2],[1,0]]
输出:0
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 100
-100 <= grid[i][j] <= 100

简单题,考察对二维数组的遍历

int countNegatives(int** grid, int gridSize, int* gridColSize){
    int cnt=0;
    int row=gridSize,col=gridColSize[0];
    for(int i=0;i<row;i++){
        for(int j=0;j<col;j++){
            cnt+=grid[i][j]<0;
        }
    }
    return cnt;
}

在这里插入图片描述

2.1572. 矩阵对角线元素的和

原题链接

给你一个正方形矩阵 mat,请你返回矩阵对角线元素的和。
请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。
示例 1:
输入:mat = [[1,2,3],
[4,5,6],
[7,8,9]]
输出:25
解释:对角线的和为:1 + 5 + 9 + 3 + 7 = 25
请注意,元素 mat[1][1] = 5 只会被计算一次。
示例 2:
输入:mat = [[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]]
输出:8
示例 3
输入:mat = [[5]]
输出:5

仍然是对矩阵的遍历但是要注意数组中重复的元素只会算一次.

int diagonalSum(int** mat, int matSize, int* matColSize){
    bool vis[matSize][matColSize[0]];
    memset(vis,0,sizeof(vis));
    int ans=0;
    for(int i=0;i<matSize;i++){
        ans+=mat[i][i];
        vis[i][i]=true;
    }
    for(int i=matColSize[0]-1;i>=0;i--){
        if(!vis[matColSize[0]-i-1][i])
        ans+=mat[matColSize[0]-i-1][i];
    }
    return ans;
}

在这里插入图片描述

3.1672. 最富有客户的资产总量

原题链接

给你一个 m x n 的整数网格 accounts ,其中 accounts[i][j] 是第 i​​​​​​​​​​​​ 位客户在第 j 家银行托管的资产数量。返回最富有客户所拥有的 资产总量 。
客户的 资产总量 就是他们在各家银行托管的资产数量之和。最富有客户就是 资产总量 最大的客户。
示例 1:
输入:accounts = [[1,2,3],[3,2,1]]
输出:6
解释:
第 1 位客户的资产总量 = 1 + 2 + 3 = 6
第 2 位客户的资产总量 = 3 + 2 + 1 = 6
两位客户都是最富有的,资产总量都是 6 ,所以返回 6 。
示例 2:
输入:accounts = [[1,5],[7,3],[3,5]]
输出:10
解释:
第 1 位客户的资产总量 = 6
第 2 位客户的资产总量 = 10
第 3 位客户的资产总量 = 8
第 2 位客户是最富有的,资产总量是 10
示例 3:
输入:accounts = [[2,8,7],[7,1,3],[1,9,5]]
输出:17
提示
m == accounts.length
n == accounts[i].length
1 <= m, n <= 50
1 <= accounts[i][j] <= 100

遍历矩阵求每一行的和最后返回最大值即可.

int max(int a,int b){
    return a>b?a:b;
}
int maximumWealth(int** accounts, int accountsSize, int* accountsColSize){
    int row=accountsSize,col=accountsColSize[0];
    int ans=INT_MIN;
    for(int i=0;i<row;i++){
        int tmp=0;
        for(int j=0;j<col;j++){
            tmp+=accounts[i][j];
        }
        ans=max(ans,tmp);
    }
    return ans;
}

在这里插入图片描述

4.766. 托普利茨矩阵

原题链接

给你一个 m x n 的矩阵 matrix 。如果这个矩阵是托普利茨矩阵,返回 true ;否则,返回 false 。
如果矩阵上每一条由左上到右下的对角线上的元素都相同,那么这个矩阵是 托普利茨矩阵 。
示例 1:
输入:matrix = [[1,2,3,4],[5,1,2,3],[9,5,1,2]]
输出:true
解释:
在上述矩阵中, 其对角线为:
“[9]”, “[5, 5]”, “[1, 1, 1]”, “[2, 2, 2]”, “[3, 3]”, “[4]”。
各条对角线上的所有元素均相同, 因此答案是 True 。
示例 2:
输入:matrix = [[1,2],[2,2]]
输出:false
解释:
对角线 “[1, 2]” 上的元素不同。

吧矩阵分为上下部分,分别判断上下部分即可.

bool isToeplitzMatrix(int** matrix, int matrixSize, int* matrixColSize){
    int row=matrixSize,col=matrixColSize[0];
    for(int i=0;i<row;i++){
        int c=0;
        int r=i;
        int prev=-1;
        while(r<row&&c<col){
            if(prev!=-1){
                if(prev!=matrix[r][c]){
                    return false;
                }
            }
            prev=matrix[r++][c++];
        }
    }
    for(int i=1;i<col;i++){
        int r=0;
        int c=i;
        int prev=-1;
        while(r<row&&c<col){
            if(prev!=-1){
                if(prev!=matrix[r][c]){
                    return false;
                }
            }
            prev=matrix[r++][c++];
        }
    }
    return true;
}

在这里插入图片描述

5.1380. 矩阵中的幸运数

给你一个 m * n 的矩阵,矩阵中的数字 各不相同 。请你按 任意 顺序返回矩阵中的所有幸运数。
幸运数 是指矩阵中满足同时下列两个条件的元素:
在同一行的所有元素中最小
在同一列的所有元素中最大
示例 1:
输入:matrix = [[3,7,8],[9,11,13],[15,16,17]]
输出:[15]
解释:15 是唯一的幸运数,因为它是其所在行中的最小值,也是所在列中的最大值。
示例 2:
输入:matrix = [[1,10,4,2],[9,3,8,7],[15,16,17,12]]
输出:[12]
解释:12 是唯一的幸运数,因为它是其所在行中的最小值,也是所在列中的最大值。
示例 3:
输入:matrix = [[7,8],[1,2]]
输出:[7]
解释:7是唯一的幸运数字,因为它是行中的最小值,列中的最大值。
提示:
m == mat.length
n == mat[i].length
1 <= n, m <= 50
1 <= matrix[i][j] <= 10^5
矩阵中的所有元素都是不同的

这个题想必很多人都做过,他的另一个名称是寻找数组中的鞍点,这这里就介绍一种简单且易懂的方法:即是利用两个数组分别存储二维数组中每行的最小值和每列的最大值最后遍历判断元素是否符合条件即可.

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int max(int a,int b){
    return a>b?a:b;
}
int min(int a,int b){
    return a<b?a:b;
}
int* luckyNumbers (int** matrix, int matrixSize, int* matrixColSize, int* returnSize){
    int row=matrixSize,col=matrixColSize[0];
    int *ans=(int *)malloc(sizeof(int)*row*col);
    *returnSize=0;
    int max_[55],min_[55];
    for(int i=0;i<col;i++){
        max_[i]=INT_MIN;
        for(int j=0;j<row;j++){
            max_[i]=max(matrix[j][i],max_[i]);
        }
    }
    for(int i=0;i<row;i++){
        min_[i]=INT_MAX;
        for(int j=0;j<col;j++){
            min_[i]=min(matrix[i][j],min_[i]);
        }
    }
    for(int i=0;i<row;i++){
        for(int j=0;j<col;j++){
            if(matrix[i][j]==max_[j]&&matrix[i][j]==min_[i]){
                ans[(*returnSize)++]=matrix[i][j];
            }
        }
    }
    return ans;
}

在这里插入图片描述

6.1582. 二进制矩阵中的特殊位置

原题链接

给你一个大小为 rows x cols 的矩阵 mat,其中 mat[i][j] 是 0 或 1,请返回 矩阵 mat 中特殊位置的数目 。
特殊位置 定义:如果 mat[i][j] == 1 并且第 i 行和第 j 列中的所有其他元素均为 0(行和列的下标均 从 0 开始 ),则位置 (i, j) 被称为特殊位置。
示例 1:
输入:mat = [[1,0,0],
[0,0,1],
[1,0,0]]
输出:1
解释:(1,2) 是一个特殊位置,因为 mat[1][2] == 1 且所处的行和列上所有其他元素都是 0
示例 2:
输入:mat = [[1,0,0],
[0,1,0],
[0,0,1]]
输出:3
解释:(0,0), (1,1) 和 (2,2) 都是特殊位置
示例 3:
输入:mat = [[0,0,0,1],
[1,0,0,0],
[0,1,1,0],
[0,0,0,0]]
输出:2
示例 4:
输入:[[0,0,0,0,0],
[1,0,0,0,0],
[0,1,0,0,0],
[0,0,1,0,0],
[0,0,0,1,1]]
输出:3
提示:
rows == mat.length
cols == mat[i].length
1 <= rows, cols <= 100
mat[i][j] 是 0 或 1

这道题有两种方法,第一是和上题类似即是用两个数组分别统计每行每列中1的个数最后再遍历数组查看每个为1的元素是否符合条件,这种方案的时间复杂度是 O ( n 2 ) O(n^2) O(n2),另一种就是遍历每一个为1的元素来进行检测,时间复杂度也是 O ( n 2 ) O(n^2) O(n2)这里介绍一下第二种

bool check(int **mat,int nr,int nc,int row,int col){
    for(int i=0;i<row;i++){
        if(i==nr){
            continue;
        }
        if(mat[i][nc]==1){
            return false;
        }
    }
    for(int i=0;i<col;i++){
        if(i==nc){
            continue;
        }
        if(mat[nr][i]==1){
            return false;
        }
    }
    return true;
}
int numSpecial(int** mat, int matSize, int* matColSize){
    int row=matSize,col=matColSize[0];
    int ans=0;
    for(int i=0;i<row;i++){
        for(int j=0;j<col;j++){
            if(mat[i][j]==1){
                ans+=check(mat,i,j,row,col);
            }
        }
    }
    return ans;
}

在这里插入图片描述

7.岛屿的周长

原题链接

给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
示例 1:
输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16
示例 2:
输入:grid = [[1]]
输出:4
示例 3:
输入:grid = [[1,0]]
输出:4
提示:
row == grid.length
col == grid[i].length
1 <= row, col <= 100
grid[i][j] 为 0 或 1

这是一道搜索题的最基础版本,我们看题目要求我们返回岛屿的周长,现在来思考岛屿的周长都来自哪里:
1 ) 1) 1):假如当前格子为陆地,那么他的四条边被算到岛屿的周长中的情况是:
 1:假如某条边的旁边是海洋,那么应该算上。
 2.假如某条边正好是矩阵的边界,也应该算上。
2 ) 2) 2):那么现在清楚了周长的来源,应该怎么求解就成了关键。容易想到,当某个格子是陆地的时候我们去看他的上下左右四个方向,如果符合加入周长的条件那么答案++,如果是海洋则跳过.那么为了方便我们定义一个 d i r [ 4 ] [ 2 ] dir[4][2] dir[4][2]数组表示四个方向方便遍历.

int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int islandPerimeter(int** grid, int gridSize, int* gridColSize){
    int ans=0;
    int row=gridSize,col=gridColSize[0];
    int x,y,nx,ny;
    for(int i=0;i<row;i++){
        for(int j=0;j<col;j++){
            if(grid[i][j]==0){
                continue;
            }
            x=i,y=j;
            for(int k=0;k<4;k++){
                nx=x+dir[k][0];
                ny=y+dir[k][1];
                if(nx==row||nx==-1||ny==col||ny==-1||grid[nx][ny]==0){
                    ans++;
                }
            }
        }
    }
    return ans;
}

在这里插入图片描述

三,今日收获

本文章的题目均来自英雄哪里出来的LeetCode零基础指南专栏:《LeetCode零基础指南》(第七讲) 二维数组,对于二维数组较为基础的是处理行与列的关系,遍历,搜索等问题,这些熟练之后并不难.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值