Day03 二维数组

  1. 根据某个元素的行列索引计算另一个元素的行列索引
  2. 在二维数组中行走遍历
  3. 根据二维数组某些元素计算另一个元素值

867. 转置矩阵

867. 转置矩阵 - 力扣(LeetCode) (leetcode-cn.com)

image-20210725224957948

(下图中右边第二行依次为(2,5,8)画图时错误

image-20210725225047789

思路:

当行数和列数相等时,每一个元素的行和列互换即可。

[i,j]放在[j,i]的位置上

解答

var transpose = function(matrix) {
    let m = matrix.length
    let n = matrix[0].length

    const newArr = []

    for(let i = 0; i < m; i++) {
        for(let j = 0; j < n; j++) {
            if(!newArr[j]) newArr[j] = []
          	// 交换位置
            newArr[j][i] = matrix[i][j]
        }
    }
    return newArr
};

48. 旋转图像

48. 旋转图像 - 力扣(LeetCode) (leetcode-cn.com)

对于矩阵中第row行的第col列元素,在旋转后,出现在倒数第row列的第col行。

matrix[row][col] —> matrix[col][n-row-1]

image-20210726175641751

解法一:暴力解法

生成一个新的二维数组,旋转原数组的内容,然后拷贝到原数组。

时间和空间复杂度都为O(n*n),不符合题目要求。

解法二:循环替换

我们逐个替换,发现如下规律

matrix[row][col] —> matrix[col][n-row-1]

matrix[col][n-row-1] —> matrix[n-row-1][n-col-1]

matrix[n-row-1][n-col-1] —> matrix[n-col-1][row]

matrix[n-col-1][row] —> matrix[row][col]

image-20210726180912950

一次可以替换4个元素

如果n为偶数,则需要替换 n*n / 4 = (n/2)*(n/2)次

如果n为奇数,中间的替换之后还在原位置,需要替换(n*n - 1) / 4 = ((n-1)/2)((n+1)/2)次

image-20210726181802834

var rotate = function(matrix) {
    let n = matrix.length
    // 使用Math.floor()方法
    for(let row = 0; row <Math.floor(n/2);row++){
        for(let col = 0; col < Math.floor((n+1)/2); col++){
            let temp = matrix[row][col]
            matrix[row][col] = matrix[n-col-1][row];
            matrix[n-col-1][row] = matrix[n-row-1][n-col-1]
            matrix[n-row-1][n-col-1] = matrix[col][n-row-1]
            matrix[col][n-row-1] = temp
        }
    }
    return matrix
};

解法三:原地翻转

我们知道matrix[row][col] —> matrix[col][n-row-1]

可以通过水平翻转的方式转换

image-20210726183319234

再经过一次主对角线翻转就可以了

image-20210726183431735

var rotate = function(matrix) {
    let n = matrix.length
    // 水平翻转
    for(let row = 0; row < Math.floor(n/2);row++){
        for(let col = 0; col < n;col++){
            let temp = matrix[row][col]
            matrix[row][col] = matrix[n-row-1][col]
            matrix[n-row-1][col] = temp;
        }
    }
    // 主对角线翻转
    for(let row = 0; row <n;row++){
        for(let col = 0; col < row;col++){
            let temp = matrix[row][col]
            matrix[row][col] = matrix[col][row]
            matrix[col][row] = temp
        }
    }
    return matrix
};

36. 有效的数独

36. 有效的数独 - 力扣(LeetCode) (leetcode-cn.com)

思路

针对给定的二维数组,我们初始化3个二维数组,第一个二维数组用来判定行是否符合,也就是说在给定的二维数组中,第一行内的数字对应的索引在第一个二维数组中的行进行标记。

第一行出现了,5,3,7三位数字,则在我们创建的第一个二维数组中第一行,5,3,7的对应位置也就是4,2,6进行标记,如果该行出现了重复的标记,则说明第一行出现了重复的数字,不是有效的数独,逐行标记,直到整个二维数组遍历完全。

类似,第二个数组用于标记列,第一列出现的数字在第二个定义的数组中进行标记,直到遍历完全。

第三个用于判断每一个模块,如果判定一个索引对应的模块位置呢,可以使用index = row/3 +(col/3)*3计算,这也很好理解,对于9个模块。对于第一个模块出现的元素标记在第一行里。

image-20210726193512375

image-20210726192138441

解答

var isValidSudoku = function(board) {
    const rowUsed = new Array(9).fill(0).map(() =>new Array(9).fill(false) )
    const colUsed = new Array(9).fill(0).map(() =>new Array(9).fill(false) )
    const boxUsed = new Array(9).fill(0).map(() =>new Array(9).fill(false) )

    for(let row = 0; row < board.length; row++){
        for(col = 0; col < board[0].length; col++) {
            if(board[row][col] !== '.') {
                // 1. 计算当前的值
                const num = board[row][col] - '1'
                // 行标记数组是否标记
                if(rowUsed[row][num]) return false
                else rowUsed[row][num] = true
							// 列标记
                if(colUsed[col][num]) return false
                else colUsed[col][num] = true
							// 3*3盒子标记
                const boxIndex = Math.floor(row/3) + Math.floor(col / 3) *3
                if(boxUsed[boxIndex][num]) return false
                else boxUsed[boxIndex][num] = true
            }
        }
    }
    return true
};

73. 矩阵置零

方案一:暴力解法

遍历整个二维数组

时间复杂度为O(mn)

空间复杂度为O(m*n)

image-20210727093000641

方案2:降低空间复杂度

时间复杂度O(mn)

空间复杂度为O(m+n)

image-20210727093548158

方案3:常量级别的空间复杂度

遍历第一行,如果遇到0,则标记变量flagRow = true,

遍历第一列,如果遇到0,则标记变量flagCol = true。

从第二行第二列开始遍历,如果第二行某个位置有0,则matrix[0][col] = 0,matrix[row][0] = 0

方案4:优化

为了防止每一列的第一个元素被提前更新,从最后一行开始,倒序处理矩阵元素

var setZeroes = function(matrix) {
   const m = matrix.length, n = matrix[0].length
    let flagCol1 = false

    for (let row = 0; row < m; row++) {
        // 第一列出现了0
        if (matrix[row][0] == 0) flagCol1 = true
        for (let col = 1; col < n; col++) {
            if (matrix[row][col] == 0) {
                matrix[row][0] = 0
                matrix[0][col] = 0
            }
        }
    }

    for (let row = m - 1; row >= 0; row--) {
        for (let col = 1; col < n; col++) {
            if (matrix[row][0] == 0 || matrix[0][col] == 0) {
                matrix[row][col] = 0
            }
        }
        if (flagCol1) matrix[row][0] = 0
    }
};

54. 螺旋矩阵

54. 螺旋矩阵 - 力扣(LeetCode) (leetcode-cn.com)

方案一

image-20210727101902996

var spiralOrder1 = function(matrix) {
    const m = matrix.length, n = matrix[0].length

    const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]]
    let row = 0, col = 0, di = 0

    const res = new Array(m * n).fill(0)
    const seen = new Array(m).fill(0).map(() => new Array(n).fill(false))

    for (let i = 0; i < m * n; i++) {
        res[i] = matrix[row][col]
        seen[row][col] = true

        const nextRow = row + dirs[di][0]
        const nextCol = col + dirs[di][1]

        if (nextRow < 0 || nextRow >= m
                || nextCol < 0 || nextCol >= n
                || seen[nextRow][nextCol]) {
            di = (di + 1) % 4
        }

        row = row + dirs[di][0]
        col = col + dirs[di][1]
    }

    return res
};

方案二

image-20210727105302892

var spiralOrder = function(matrix) {
    let startRow = 0, endRow = matrix.length - 1
    let starCol = 0, endCol = matrix[0].length - 1

    const res = []

    while (startRow <= endRow && starCol <= endCol) {
        // top 行
        for (let col = starCol; col <= endCol; col++) res.push(matrix[startRow][col])
        // right 列
        for (let row = startRow + 1; row <= endRow; row++) res.push(matrix[row][endCol])
      // 边界条件:只有一行或者只有一列
        if (startRow < endRow && starCol < endCol) {
            // bottom 行
            for (let col = endCol - 1; col > starCol; col--) res.push(matrix[endRow][col])
            // left 列
            for (let row = endRow; row > startRow; row--) res.push(matrix[row][starCol])
        }
        startRow++
        endRow--
        starCol++
        endCol--
    }
    return res
};

59. 螺旋矩阵二

59. 螺旋矩阵 II - 力扣(LeetCode) (leetcode-cn.com)

var generateMatrix = function(n) {

    const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]]
    let row = 0, col = 0, di = 0

    const res = new Array(n).fill(0).map(() => new Array(n).fill(0))
    const seen = new Array(n).fill(0).map(() => new Array(n).fill(false))

    for (let i = 0; i < n * n; i++) {
        res[row][col] = i + 1
        seen[row][col] = true

        const nextRow = row + dirs[di][0]
        const nextCol = col + dirs[di][1]

        if (nextRow < 0 || nextRow >= n
                || nextCol < 0 || nextCol >= n
                || seen[nextRow][nextCol]) {
            di = (di + 1) % 4
        }

        row = row + dirs[di][0]
        col = col + dirs[di][1]
    }

    return res
};

498. 对角线遍历

image-20210727111254171

斜上走法:row-1,col+1

斜下走法:row+1,col-1

row<0: row = 0, col不变,换方向

col<0: row不变,col=0,换方向

image-20210727112000427

image-20210727112305821

对于边界的条件是有执行顺序的。

var findDiagonalOrder = function(matrix) {
    const m = matrix.length
    if (m == 0) return []
    const n = matrix[0].length

    const result = new Array(m * n).fill(0)
    const dirs = [[-1, 1], [1, -1]]
    let row = 0, col = 0, d = 0

    for (let i = 0; i < m * n; i++) {
        result[i] = matrix[row][col]
        row += dirs[d][0]
        col += dirs[d][1]

        if (row >= m) {row = m - 1; col += 2; d = 1 - d;}
        if (col >= n) {col = n - 1; row += 2; d = 1 - d;}
        if (row < 0) {row = 0; d = 1 - d;}
        if (col < 0) {col = 0; d = 1 - d;}
    }

    return result

};

118. 杨辉三角

image-20210727120247248

118. 杨辉三角 - 力扣(LeetCode) (leetcode-cn.com)

var generate = function(numRows) {
    const rows = []
    for(let row = 0; row < numRows; row++) {
        // 每行数组的第一个位置是1,长度是row + 1
        const oneRow = new Array(row+1).fill(1)
        for(let col = 1; col < row; col++) {
            oneRow[col] = rows[row-1][col-1] + rows[row-1][col]
        }
        rows.push(oneRow)
    }
    return rows
};

119. 杨辉三角2

要求空间复杂度为O(k)

从后遍历,将前面一行的数据存在数组中,当计算n行的数据时,从后往前计算求得第n行的数据

var getRow = function(rowIndex) {
    const oneRow = new Array(rowIndex + 1).fill(0)
    oneRow[0] = 1
    for (let row = 1; row <= rowIndex; row++) {
        for (let col = row; col > 0; col--) {
            oneRow[col] += oneRow[col - 1]
        }
    }
    return oneRow
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值