【第6期】面试BAT前应该知道的二维数组

简介: 【第6期】面试BAT前应该知道的二维数组

考察数组下标规律和边界


此类问题,重点是从数组的下标中发现规律,写代码的时候要注意程序的边界问题,常见于Z字形打印二维数组、蛇形打印二维数组、杨辉三角等等问题。


杨辉三角


LeetCode.118,难度简单


题目


给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 示例:

输入: 5

输出:

[ [1],

[1,1],

[1,2,1],

[1,3,3,1],

[1,4,6,4,1] ]


思路


观察给出的例子,可以发现规律,比如对于arr1=[1,2,1]和arr2=[1,3,3,1]来说:


image.png

可以看出规律来:

  1. arr2[0] = 1
  2. arr2[1] = arr1[0] + arr1[1]
  3. arr2[2] = arr1[1] + arr1[2]
  4. arr[3] = 1

反过来思路就是:

  • 遍历arr1,index=0时,arr2.push(1)
  • 如果index=arr1.length-1,arr2.push(1)
  • 否则,arr2.push(arr1[index] + arr1[index+1])


代码


/**
 * @param {number} numRows
 * @return {number[][]}
 */
var generate = function(n) {
  if(n === 0)
    return [];
  if(n === 1)
    return [ [1] ];
  let res = [[1]];
  for(let i = 1;i < n;i++) {
    let lastArr = res[i-1];
    let newArr = [];
    for(let j = 0;j < lastArr.length;j++) {
      if(j === 0)
          newArr.push(1);
      if(j === lastArr.length-1)
        newArr.push(1);
      else {
        newArr.push(lastArr[j]+lastArr[j+1]);
      }
    }
    res.push(newArr);
  }
  return res;
};
复制代码


对角线遍历二维数组


LeetCode.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. (0,0)
  2. (0,1), (1,0)
  3. (2,0), (1,1), (0,2)
  4. (0,3), (1,2), (2,1)
  5. (2,2), (1,3)
  6. (2,3)

[

A, B, C, D,

E, F, G, H,

I, J, K, L

]

可以看出来一些规律:

  • 按打印一次对角线来算,一共要打印6次,也就是行数+列数-1次
  • 按最开始那一次算第count=0次的话,如果count小于行数,那x=count且y=count-x,否则x=行数-1且y=count-x,对于列数来说也是一样的道理


代码


/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var findDiagonalOrder = function(matrix) {
    if(matrix === null || matrix.length === 0 || matrix[0].length === 0)
        return [];
    let rows = matrix.length;
    let cols = matrix[0].length;
    let count = 0;
    let res = [];
    while(count < rows+cols-1) {
        let r1 = count < rows ? count : rows-1;
        let c1 = count - r1;
        while(r1 >= 0 && c1 < cols) {
            res.push(matrix[r1][c1]);
            r1--;
            c1++;
        }
        count++;
        if(count >= rows+cols-1)
            break;
        let c2 = count < cols ? count : cols-1;
        let r2 = count - c2;
        while(c2 >= 0 && r2 < rows) {
            res.push(matrix[r2][c2]);
            r2++;
            c2--;
        }
        count++
    }
    return res;
};
复制代码


螺旋矩阵


LeetCode.54,难度中等


题目


给定一个包含 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]


思路


从题目给出的例子可以看出,螺旋遍历矩阵其实就是按照顺时针一层一层的遍历。注意好边界的划分,以及特殊情况比如一行和一列的处理。



image.png

image.png

代码


/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var traverseLayer = function(m, startRow, endRow, startCol, endCol, res) {
    if(startRow === endRow) {
    // 一列的情况
        for(let i = startCol;i <= endCol;i++) {
            res.push(m[startRow][i]);
        }
    } else if(startCol === endCol) {
        for(let i = startRow;i <= endRow;i++) {
            res.push(m[i][startCol]);
        }
    } else {
        let curR = startRow;
        let curC = startCol;
        while(curC < endCol) {
            res.push(m[curR][curC]);
            curC++;
        }
        while(curR < endRow) {
            res.push(m[curR][curC]);
            curR++;
        }
        while(curC > startCol) {
            res.push(m[curR][curC]);
            curC--;
        }
        while(curR > startRow) {
            res.push(m[curR][curC]);
            curR--;
        }
    }
}
var spiralOrder = function(matrix) {
    if(matrix === void 0 || matrix.length === 0 || matrix[0].length === 0)
        return [];
    let res = [];
    let startRow = 0;
    let endRow = matrix.length-1;
    let startCol = 0;
    let endCol = matrix[0].length-1;
    while(startRow <= endRow && startCol <= endCol) {
        traverseLayer(matrix, startRow, endRow, startCol, endCol, res);
        startRow++;
        endRow--;
        startCol++;
        endCol--;
    }
    return res;
};
复制代码


考察递归思路


对于此类问题,最重要的是要注意到不是简单地找数组下标的规律就能解决的,要把问题抽象成递归的思路,递归入口、递归调用、递归结束条件,这三点缺一不可。


朋友圈


LeetCode.547,难度中等


题目


班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。

给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。

示例 1:

输入:

[[1,1,0],

[1,1,0],

[0,0,1]]

输出: 2

说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 第2个学生自己在一个朋友圈。所以返回2。

示例 2:

输入:

[[1,1,0],

[1,1,1],

[0,1,1]]

输出: 1

说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。

注意: N 在[1,200]的范围内。 对于所有学生,有M[i][i] = 1。 如果有M[i][j] = 1,则有M[j][i] = 1。


思路


看一下这道题的示例,可以看出来如果arr[0,1]=1,0和1是朋友,那接下来就要去检查1和其他的人是否是朋友,再依次检查下去,说到这里就可以考虑深度优先的搜索方法了。


代码


/**
 * @param {number[][]} M
 * @return {number}
 */
var findCircleNum = function(M) {
    // 深度优先
    let visited = [];
    for(let i = 0;i < M.length;i++) {
        visited.push(false);    
    }
    let res = 0;
    for(let i = 0;i < visited.length;i++) {
        if(visited[i]) 
            continue;
        traverse(M, i, visited);
        res++;
    }
    return res;
};
function traverse(M, cur, visited) {
    visited[cur] = true;
    for(let i = 0;i < M.length;i++) {
        if(visited[i] || !M[cur][i])
            continue;
        traverse(M, i, visited);
    }
}
复制代码


岛屿的最大面积


LeetCode.695,难度中等


题目


给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。

找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为0。)

示例 1:

[[0,0,1,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,0,0,0], [0,1,1,0,1,0,0,0,0,0,0,0,0], [0,1,0,0,1,1,0,0,1,0,1,0,0], [0,1,0,0,1,1,0,0,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,0,0], [0,0,0,0,0,0,0,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,0,0,0,0]]

对于上面这个给定矩阵应返回6。

注意答案不应该是11,因为岛屿只能包含水平或垂直的四个方向的‘1’。

示例 2:

[[0,0,0,0,0,0,0,0]]

对于上面这个给定的矩阵, 返回 0。

注意: 给定的矩阵grid 的长度和宽度都不超过 50。

思路


对于[[1,1,0,0,0],[1,1,0,0,0],[0,0,0,1,1],[0,0,0,1,1]]这样的矩阵来说,从最左上角的1出发,分别再考察它的四周(上下左右)是否为1,它的上下左右再考察自己的四周是否为1,遇到是1则可以加1,遇到是0则不处理即可,说到这里基本就可以确定可以使用递归了,即有一个自己调用自己的过程;这里面有个细节,处理过的1需要置为0,否则会有重复计算的问题。

代码如下:

/**
 * @param {number[][]} grid
 * @return {number}
 */
var maxAreaOfIsland = function(grid) {
    if(grid === null || grid.length === 0)
        return 0;
    let res = 0;
    for(let i = 0;i < grid.length;i++) {
        for(let j = 0;j < grid[0].length;j++) {
            if(grid[i][j] === 1)
                res = Math.max(res, help(grid, i, j));
        }
    }
    return res;
};
var help = function(grid, i, j) {
    grid[i][j] = 0;
    let sum = 1;
    if(i > 0 && grid[i-1][j] === 1)
        sum += help(grid, i-1, j);
    if(i < grid.length-1 && grid[i+1][j] === 1) 
        sum += help(grid, i+1, j);
    if(j > 0 && grid[i][j-1] === 1)
        sum += help(grid, i, j-1);
    if(j < grid[0].length-1 && grid[i][j+1] === 1)
        sum += help(grid, i, j+1);
    return sum;
}


相关文章
|
6月前
|
NoSQL Java 关系型数据库
BAT最新java800+合集面试复盘,能掌握80%就去进BATJTMD
金三银四俗称跳槽黄金期,很多同学都想趁着这段时间拿高薪,去更牛逼的公司工作,认识更多大牛,提升自己的职场竞争力。 那怎样才能通T面试官的考核?怎样成为一名Offer收割机? 之前讲过收割Offer有一个最直接的公示:Offer=硬实过BAT面试官的考核?怎样成为一名Offer收割机? 之前讲过收割Offer有一个最直接的公示:Offer=硬实力*软实力*好的心态,三者缺一不可。
|
算法 C++
【面试必刷TOP101】二分查找-I & 二维数组中的查找
【面试必刷TOP101】二分查找-I & 二维数组中的查找
52 0
|
6月前
(力扣)面试题04. 二维数组中的查找
(力扣)面试题04. 二维数组中的查找
37 0
|
6月前
|
定位技术 API
Angular 调用导入百度地图API接口,2024春招BAT面试真题详解
Angular 调用导入百度地图API接口,2024春招BAT面试真题详解
|
6月前
|
JavaScript 前端开发 算法
JQuery 基本使用,2024BAT大厂Web前端社招面试题
JQuery 基本使用,2024BAT大厂Web前端社招面试题
JQuery 基本使用,2024BAT大厂Web前端社招面试题
|
6月前
|
C++
【一刷《剑指Offer》】面试题 3:二维数组中的查找
【一刷《剑指Offer》】面试题 3:二维数组中的查找
|
6月前
|
算法 安全 Java
2024年Android最新知识体系最强总结(全方面覆盖Android知识结构,BAT面试&学习进阶)
2024年Android最新知识体系最强总结(全方面覆盖Android知识结构,BAT面试&学习进阶)
|
6月前
|
设计模式 Java 关系型数据库
BAT等大厂年薪30W+面试清单:JVM\MySQL\设计模式\分布式\微服务
疫情影响下招聘名额缩减不少,但阿里、腾讯、抖音、快手等互联网公司却加快了人才招聘的节奏。这里根据自身的实际经历,整理了一份面试这些大厂的清单,希望能帮助到大家查漏补缺,攻克面试难关。
|
6月前
LeetCode(面试题:二维数组中的查找)
LeetCode(面试题:二维数组中的查找)
40 0
|
前端开发 关系型数据库 MySQL
学会这些BAT大厂高频面试题,进大厂完成有希望!!!
学会这些BAT大厂高频面试题,进大厂完成有希望!!!
下一篇
无影云桌面