867.矩阵转置
给你一个二维整数数组 matrix, 返回 matrix 的 转置矩阵 。
矩阵的 转置 是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[1,4,7],[2,5,8],[3,6,9]]
示例 2:
输入:matrix = [[1,2,3],[4,5,6]]
输出:[[1,4],[2,5],[3,6]]
思路
对于col不等row的二维数组,申请一个新的二位数组, newMatrix[col][row],然后[i,j] ->[j,i],对于col等于row也是一样处理
代码
/**
* @param {number[][]} matrix
* @return {number[][]}
*/
var transpose = function(matrix) {
const row = matrix.length;
const col = matrix[0].length;
const newMatrix = [];
for(let i = 0; i < row; i++){
for(let j = 0; j < col; j++){
if(!newMatrix[j]) newMatrix[j] = [];
newMatrix[j][i] = matrix[i][j]
}
}
return newMatrix;
};
47.旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[[7,4,1],[8,5,2],[9,6,3]]
解法一原地旋转
/**
* 思路
* n是偶数,一共有n^2个数,每次可以放对4个数,需要操作n^2 /4 = (n/2)*(n/2)次
* n是奇数, 矩阵最中间的数,无法替换,需要替换 n^2-1个数,每次可以放对4个数,需要操作(n^2-1)/4 = (n-1)/2 * (n+1)/2
* 对于偶数(n/2) 和奇数(n-1)/2,结果都可以用 n/2表示
* 对于偶数和奇数(n+1)/2,结果一样,可以用(n+1)/2
* 交换等式 arr[row][col] -> arr[col][n-row-1],然后推导四次交换的下标
* @param {number[][]} matrix
* @return {void} Do not return anything, modify matrix in-place instead.
*/
var rotate = function (matrix) {
const n = matrix.length;
for (let row = 0; row < Math.floor(n / 2); row++) {
for (let col = 0; col < Math.floor((n + 1) / 2); col++) {
const temp = 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] = matrix[row][col];
matrix[row][col] = temp;
}
}
};
解法二原地翻转
/**
思路2
目标是 arr[row][col] -> arr[col][n-row-1]
可以拆解为水平翻转,然后对角线翻转
arr[row][col] -> arr[n-row-1][col] -> arr[col][n-row-1]
*/
const n = matrix.length;
// 水平翻转
for (let row = 0; row < Math.floor(n / 2); row++) {
for (let col = 0; col < n; col++) {
const 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++) {
// 注意这里是col < row,不是col < n,因为是在原二维数组对角线进行翻转,而不是新申请的二维数组
for (let col = 0; col < row; col++) {
const temp = matrix[row][col];
matrix[row][col] = matrix[col][row];
matrix[col][row] = temp;
}
}
36.有效的数独
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
注意:
一个有效的数独(部分已被填充)不一定是可解的。 只需要根据以上规则,验证已经填入的数字是否有效即可。 空白格用 '.' 表示。
代码
/**
* @param {character[][]} board
* @return {boolean}
*/
var isValidSudoku = function(board) {
const rowUsed = new Array(9).fill(0).map(()=>new Array(9).fill(0));
const colUsed = new Array(9).fill(0).map(()=>new Array(9).fill(0));
const boxUsed = new Array(9).fill(0).map(()=>new Array(9).fill(0));
for(let i = 0; i < board.length; i++) {
for(let j = 0; j < board.length; j++) {
if(board[i][j] !== '.') {
const num = Number(board[i][j]) - 1;
// rowUsed[i][num] 表示i行num是否出现
if(rowUsed[i][num]) {
return false;
} else {
rowUsed[i][num] = true;
}
if(colUsed[j][num]) {
return false
} else {
colUsed[j][num] = true;
}
const boxIndex = (Math.floor( i / 3 )) + (Math.floor( j / 3)) * 3;
if(boxUsed[boxIndex][num]) {
return false
} else {
boxUsed[boxIndex][num] = true;
}
}
}
}
return true;
};
73.矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
解法一
/**
* @param {number[][]} matrix
* @return {void} Do not return anything, modify matrix in-place instead.
*/
时间复杂度 O(m*n) 空间复杂度 O(m + n)
var setZeroes = function(matrix) {
const m = matrix.length;
const n = matrix[0].length;
// 记录当前行和列是否需要设置为0
const rows = new Array(m).fill(false);
const cols = new Array(n).fill(false);
for(let i = 0; i < m; i++){
for(let j = 0; j < n; j++){
if(matrix[i][j] === 0) {
rows[i] = true;
cols[j] = true;
}
}
}
for(let i = 0; i < m; i++){
for(let j = 0; j < n; j++){
if(rows[i] || cols[j]) {
matrix[i][j] = 0;
}
}
}
};
解法二
// 时间复杂度 O(m*n) 空间复杂度 O(1)
var setZeroes = function (matrix) {
const m = matrix.length;
const n = matrix[0].length;
// 记录第一列是否为0
let flagClo1 = false;
// 从第二列开始遍历,遇到0,就将二维数组的第一列和第一行设置为0
for (let row = 0; row < m; row++) {
// 判断第一列是否有0
if (matrix[row][0] === 0) flagClo1 = true;
for (let col = 1; col < n; col++) {
if (matrix[row][col] === 0) {
matrix[row][0] = 0;
matrix[0][col] = 0;
}
}
}
// 从最后一行的第二列开始遍历(为了避免设置为0后,覆盖),
// 遇到这一行的第一行为0(或者这一列的第一列为0),就将当前元设置为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;
}
}
// 处理每一行的第一列是否要设置为0
if(flagClo1) matrix[row][0] = 0;
}
};
54.螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
直接模拟
// 直接模拟
var spiralOrder = function (matrix) {
// 记录方向下标
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]];
const m = matrix.length;
const n = matrix[0].length;
const res = [];
let row = 0, col = 0;
let di = 0;
// 记录矩阵是否被遍历过
const used = new Array(m).fill(false).map(()=>new Array(n).fill(false));
for(let i = 0; i < m * n; i++) {
res.push(matrix[row][col]);
used[row][col] = true
let nextRow = row + dir[di][0];
let nextCol = col + dir[di][1];
// 判断是否到数组边界和下一个元素是否已经遍历过了,遍历过就要改变方向
if(nextRow < 0 || nextRow >= m
|| nextCol < 0 || nextCol >= n
|| used[nextRow][nextCol]
) {
di = ( di + 1 ) % 4;
}
row = row + dir[di][0];
col = col + dir[di][1]
}
return res;
};
按层遍历
var spiralOrder = function (matrix) {
const m = matrix.length;
const n = matrix[0].length;
let startRow = 0, startCol = 0;
let endRow = m - 1, endCol = n -1;
const res = []
while(startRow <= endRow && startCol <= endCol ) {
// 遍历上面
for(let i = startCol; i <= endCol; i++) {
res.push(matrix[startRow][i]);
}
// 遍历右边
for(let i = startRow + 1; i <= endRow; i++) {
res.push(matrix[i][endCol]);
}
// 不是一行和一列
if(startRow < endRow && startCol < endCol) {
// bottom
for(let i = endCol - 1; i >= startCol + 1; i--) {
res.push(matrix[endRow][i]);
}
// right
for(let i = endRow; i >= startRow + 1; i--) {
res.push(matrix[i][startCol]);
}
};
startRow++;
endRow--;
startCol++;
endCol--;
}
return res;
};
59.螺旋矩阵二
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function (n) {
// const dir = [[0,1], [1,0], [0,-1], [-1,0]];
// const res = new Array(n).fill(0).map(()=>new Array(n).fill(0));
// let row = 0, col = 0, di = 0;
// const seen = new Array(n).fill(false).map(()=>new Array(n).fill(false));
// for(let i = 0; i < n * n; i++) {
// res[row][col] = i + 1;
// seen[row][col] = true
// let nextRow = row + dir[di][0];
// let nextCol = col + dir[di][1];
// // 注意nextRow = n
// if(nextRow < 0 || nextRow >= n
// || nextCol < 0 || nextCol >= n
// || seen[nextRow][nextCol]
// ) {
// di = ( di + 1 ) % 4;
// }
// row = row + dir[di][0];
// col = col + dir[di][1];
// }
// return res;
let startRow = 0, endRow = n - 1;
let startCol = 0, endCol = n - 1;
const res = new Array(n).fill(0).map(() => new Array(n).fill(0));
let num = 1;
while (startRow <= endRow && startCol <= endCol) {
// 上面
for (let i = startCol; i <= endCol; i++) {
res[startRow][i] = num;
num++;
}
// 右面
for (let i = startRow + 1; i <= endRow; i++) {
res[i][endCol] = num;
num++;
}
if (startRow < endRow && startCol < endCol) {
// 下面
for (let i = endCol - 1; i >= startCol + 1; i--) {
res[endRow][i] = num;
num++;
}
// 左面
for (let i = endRow; i >= startRow + 1; i--) {
res[i][startCol] = num;
num++;
}
}
startRow++;
endRow--;
startCol++;
endCol--;
}
return res;
};
498.对角线遍历
/**
* @param {number[][]} mat
* @return {number[]}
*/
// 画一个 4 * 3推导一下
var findDiagonalOrder = function (mat) {
const m = mat.length;
const n = mat[0].length;
const dir = [[-1, 1], [1, -1]];
let row = 0, col = 0, di = 0;
const res = [];
for (let i = 0; i < m * n; i++) {
res.push(mat[row][col]);
row = row + dir[di][0];
col = col + dir[di][1];
if (row >= m) {
row = m - 1; // 不是row -1
col = col + 2;
di = 1 - di; // 换方向
}
if (col >= n) {
row = row + 2;
col = n - 1; // 不是col -1
di = 1 - di;
}
if (row < 0) {
row = 0;
di = 1 - di;
}
if (col < 0) {
col = 0;
di = 1 - di;
}
}
return res;
};
118.杨辉三角
给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
/**
* @param {number} numRows
* @return {number[][]}
*/
// 把杨辉三角看成一个一半的二维数组
var generate = function (numRows) {
const res = [];
for (let row = 0; row < numRows; row++) {
const rowArr = [];
for (let col = 0; col <= row; col++) {
// 第一列或者最后一列设置为1
if (col === 0 || col == row) {
rowArr[col] = 1;
} else {
// 将上一行上一列和上一行前一列相加
const prevRow = res[row - 1];
rowArr[col] = prevRow[col] + prevRow[col - 1];
}
}
res[row] = rowArr;
}
return res;
};
119.杨辉三角二
/**
* @param {number} rowIndex
* @return {number[]}
*/
// 用一个数组,存储,反向遍历
var getRow = function(rowIndex) {
const res = new Array(rowIndex+1).fill(0);
res[0] = 1;
for(let row = 1; row <= rowIndex; row++) {
for(let col = row; col > 0; col--) {
res[col] = res[col] + res[col-1];
}
}
return res;
};