feat: matrix leetcode 36,48,54,73,289
This commit is contained in:
parent
eb9dee4335
commit
0d078c09b4
117
top-interview-leetcode150/matrix/289生命游戏.js
Normal file
117
top-interview-leetcode150/matrix/289生命游戏.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/game-of-life/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number[][]} board
|
||||||
|
* @return {void} Do not return anything, modify board in-place instead.
|
||||||
|
*/
|
||||||
|
const gameOfLife = function (board) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
模拟:按照题目要求模拟,遍历所有的细胞,通过细胞周围的8个细胞来判断它下一次更新的状态,细胞的状态由下面的条件决定
|
||||||
|
1.细胞是活的,会有三种情况,如果周围活细胞数量小于2,那么这个细胞死亡,如果周围活细胞数量为2个或3个,那么这个细胞维持
|
||||||
|
存活状态,如果这个细胞周围的活细胞超过了三个,那么这个细胞死亡.
|
||||||
|
2.细胞是死的,如果周围正好有三个活细胞那么就复活这个细胞。
|
||||||
|
按照上面的要求我们可以把问题拆分为这样,如果这个细胞是活的 并且周围的活细胞少于两个,或者周围的活细胞大于三个,那么这个细胞死亡;
|
||||||
|
如果这个细胞是死的,周围正好有三个活细胞,那么就复活这个细胞
|
||||||
|
*/
|
||||||
|
function f1(board) {
|
||||||
|
const m = board.length - 1;
|
||||||
|
const n = board[0].length - 1;
|
||||||
|
let lives = 0; // 表示当前细胞周围的活细胞数量
|
||||||
|
const updates = []; // 细胞下一次要更新的状态
|
||||||
|
|
||||||
|
for (let i = 0; i <= m; i++) {
|
||||||
|
for (let j = 0; j <= n; j++) {
|
||||||
|
// 查看左上角的细胞是否存活
|
||||||
|
if (i > 0 && j > 0 && board[i - 1][j - 1] === 1) lives++;
|
||||||
|
// 查看上面的细胞是否存活
|
||||||
|
if (i > 0 && board[i - 1][j] === 1) lives++;
|
||||||
|
// 查看右上角的细胞是否存活
|
||||||
|
if (i > 0 && j < n && board[i - 1][j + 1] === 1) lives++;
|
||||||
|
// 查看右边的细胞是否存活
|
||||||
|
if (j < n && board[i][j + 1] === 1) lives++;
|
||||||
|
// 查看右下角的细胞是否存活
|
||||||
|
if (i < m && j < n && board[i + 1][j + 1] === 1) lives++;
|
||||||
|
// 查看下面的细胞是否存活
|
||||||
|
if (i < m && board[i + 1][j] === 1) lives++;
|
||||||
|
// 查看左下角的细胞是否存活
|
||||||
|
if (i < m && j > 0 && board[i + 1][j - 1] === lives) lives++;
|
||||||
|
// 查看左边的细胞是否存活
|
||||||
|
if (j > 0 && board[i][j - 1] === 1) lives++;
|
||||||
|
|
||||||
|
// 如果当前细胞是活的,只要它周围存活的细胞小于二,或者大于三,那么下一次更新的状态是死亡,把更新状态存入更新数组
|
||||||
|
if (board[i][j] === 1 && (lives < 2 || lives > 3)) {
|
||||||
|
updates.push(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前细胞是死的, 只要周围存活的细胞恰好等于3,那么下次更新的状态就是复活,把更新状态存入更新数组
|
||||||
|
if (board[i][j] === 0 && lives === 3) {
|
||||||
|
updates.push(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果细胞状态无需变化往更新数组插入数据-1,表示无需更新
|
||||||
|
updates.push(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过updates更新数组来更新整个board
|
||||||
|
|
||||||
|
let k = 0;
|
||||||
|
for (let i = 0; i <= m; i++) {
|
||||||
|
for (let j = 0; j <= n; j++) {
|
||||||
|
if (updates[k] >= 0) board[i][j] = updates[k];
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
利用次低位来保存下一次更新的状态,省去了updates更新数组的空间
|
||||||
|
*/
|
||||||
|
function f2(board) {
|
||||||
|
const dx = [-1, 0, 1, -1, 1, -1, 0, 1];
|
||||||
|
const dy = [-1, -1, -1, 0, 0, 1, 1, 1];
|
||||||
|
|
||||||
|
for (let i = 0; i < board.length; i++) {
|
||||||
|
for (let j = 0; j < board[0].length; j++) {
|
||||||
|
let sum = 0;
|
||||||
|
|
||||||
|
// 计算周围8个邻居的活细胞数
|
||||||
|
for (let k = 0; k < 8; k++) {
|
||||||
|
const nx = i + dx[k];
|
||||||
|
const ny = j + dy[k];
|
||||||
|
if (nx >= 0 && nx < board.length && ny >= 0 && ny < board[0].length) {
|
||||||
|
sum += (board[nx][ny] & 1); // 累加邻居细胞的最低位(表示当前活或死)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 根据规则设置细胞的未来状态
|
||||||
|
// if (board[i][j] === 1) {
|
||||||
|
// // 如果当前细胞是活的
|
||||||
|
// if (sum === 2 || sum === 3) {
|
||||||
|
// board[i][j] |= 2; // 设次低位为1,表示细胞将在下一轮继续存活
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // 如果当前细胞是死的
|
||||||
|
// if (sum === 3) {
|
||||||
|
// board[i][j] |= 2; // 设次低位为1,表示细胞将在下一轮复活
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 根据规则设置细胞的未来状态
|
||||||
|
if (sum === 3 || (board[i][j] === 1 && (sum === 2 || sum === 3))) {
|
||||||
|
board[i][j] |= 2; // 设次低位为1,表示细胞将在下一轮存活或复活
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二次遍历,更新细胞的状态
|
||||||
|
for (let i = 0; i < board.length; i++) {
|
||||||
|
for (let j = 0; j < board[i].length; j++) {
|
||||||
|
board[i][j] >>= 1; // 右移1位,更新状态为新的细胞状态
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
top-interview-leetcode150/matrix/36有效的数独.js
Normal file
63
top-interview-leetcode150/matrix/36有效的数独.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/valid-sudoku/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {character[][]} board
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const isValidSudoku = function (board) {
|
||||||
|
return f1(board);
|
||||||
|
};
|
||||||
|
|
||||||
|
function f1(board) {
|
||||||
|
const rows = Array(9).fill(null).map(() => new Set());
|
||||||
|
const cols = Array(9).fill(null).map(() => new Set());
|
||||||
|
const boxes = Array(9).fill(null).map(() => new Set());
|
||||||
|
|
||||||
|
for (let i = 0; i < 9; i++) {
|
||||||
|
for (let j = 0; j < 9; j++) {
|
||||||
|
const num = board[i][j];
|
||||||
|
if (num === '.') continue; // 空格跳过
|
||||||
|
|
||||||
|
const boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3); // 计算所在的3x3子格的索引
|
||||||
|
|
||||||
|
// 检查当前数字是否已经出现过
|
||||||
|
if (rows[i].has(num) || cols[j].has(num) || boxes[boxIndex].has(num)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将当前数字加入对应的set中
|
||||||
|
rows[i].add(num);
|
||||||
|
cols[j].add(num);
|
||||||
|
boxes[boxIndex].add(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f2(board) {
|
||||||
|
// 使用位运算加速
|
||||||
|
const rows = Array(9).fill(0);
|
||||||
|
const cols = Array(9).fill(0);
|
||||||
|
const block = Array(9).fill(0);
|
||||||
|
|
||||||
|
for (let i = 0; i < 9; i++) {
|
||||||
|
for (let j = 0; j < 9; j++) {
|
||||||
|
if (board[i][j] === '.') continue;
|
||||||
|
|
||||||
|
const x = board[i][j] - '0'; // 转换字符为数字
|
||||||
|
const blockIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3); // 计算所在的3x3子格的索引
|
||||||
|
|
||||||
|
// 检查当前数字是否已经出现过
|
||||||
|
if ((rows[i] >> x & 1) || (cols[j] >> x & 1) || (block[blockIndex] >> x & 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用位运算设置当前数字已出现
|
||||||
|
rows[i] |= 1 << x;
|
||||||
|
cols[j] |= 1 << x;
|
||||||
|
block[blockIndex] |= 1 << x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
39
top-interview-leetcode150/matrix/48旋转矩阵.js
Normal file
39
top-interview-leetcode150/matrix/48旋转矩阵.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/rotate-image/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number[][]} matrix
|
||||||
|
* @return {void} Do not return anything, modify matrix in-place instead.
|
||||||
|
*/
|
||||||
|
const rotate = function (matrix) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:
|
||||||
|
* 1. 首先进行矩阵的转置操作:将 matrix[i][j] 和 matrix[j][i] 交换,遍历时确保 i < j,避免重复交换。
|
||||||
|
* 2. 然后反转每一行,将每一行的元素顺序倒过来。
|
||||||
|
* 这两步操作完成后,矩阵就会被顺时针旋转 90 度。
|
||||||
|
*/
|
||||||
|
function f1(matrix) {
|
||||||
|
const n = matrix.length;
|
||||||
|
// 对矩阵装置
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
for (let j = i; j < n; j++) {
|
||||||
|
const tmp = matrix[i][j];
|
||||||
|
matrix[i][j] = matrix[j][i];
|
||||||
|
matrix[j][i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反转每一行
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
let left = 0;
|
||||||
|
let right = n - 1;
|
||||||
|
while (left < right) {
|
||||||
|
const tmp = matrix[i][left];
|
||||||
|
matrix[i][left] = matrix[i][right];
|
||||||
|
matrix[i][right] = tmp;
|
||||||
|
left++;
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
top-interview-leetcode150/matrix/54螺旋矩阵.js
Normal file
50
top-interview-leetcode150/matrix/54螺旋矩阵.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/spiral-matrix/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number[][]} matrix
|
||||||
|
* @return {number[]}
|
||||||
|
*/
|
||||||
|
const spiralOrder = function (matrix) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function f1(matrix) {
|
||||||
|
if (!matrix.length || !matrix[0].length) return []; // 矩阵中没有元素
|
||||||
|
const result = []; // 存放遍历的结果
|
||||||
|
// 定义四个边界的起始位置
|
||||||
|
let top = 0; // 上边界
|
||||||
|
let bottom = matrix.length - 1; // 下边界
|
||||||
|
let left = 0; // 左边界
|
||||||
|
let right = matrix[0].length - 1; // 右边界
|
||||||
|
|
||||||
|
// 开始模拟顺时针遍历,遍历结束的条件 top > bottom 或 left > right
|
||||||
|
while (left <= right && top <= bottom) {
|
||||||
|
// 从左到右遍历上边界
|
||||||
|
for (let i = left; i <= right; i++) {
|
||||||
|
result.push(matrix[top][i]);
|
||||||
|
}
|
||||||
|
top++; // 上边界下移
|
||||||
|
|
||||||
|
// 从上往下遍历右边界
|
||||||
|
for (let i = top; i <= bottom; i++) {
|
||||||
|
result.push(matrix[i][right]);
|
||||||
|
}
|
||||||
|
right--; // 右边界向左移动
|
||||||
|
|
||||||
|
if (top <= bottom) {
|
||||||
|
// 从右往左遍历下边界
|
||||||
|
for (let i = right; i >= left; i--) {
|
||||||
|
result.push(matrix[bottom][i]);
|
||||||
|
}
|
||||||
|
bottom--; // 下边界向上移动
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left <= right) {
|
||||||
|
// 从下往上遍历左边界
|
||||||
|
for (let i = bottom; i >= top; i--) {
|
||||||
|
result.push(matrix[i][left]);
|
||||||
|
}
|
||||||
|
left++; // 左边界向右移动
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
110
top-interview-leetcode150/matrix/73矩阵置零.js
Normal file
110
top-interview-leetcode150/matrix/73矩阵置零.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/set-matrix-zeroes/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number[][]} matrix
|
||||||
|
* @return {void} Do not return anything, modify matrix in-place instead.
|
||||||
|
*/
|
||||||
|
const setZeroes = function (matrix) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
遍历每一个元素,如果遍历到的元素是零就把它横竖的所有元素都设置成零,并标记这一行和这一列已经设置过了,如果在这一列遇到了某个元素
|
||||||
|
也是0,那么就检查行标记是否已经右这一行,如果有就不处理,如果没有设置这一行的所有元素为0,并标记这一行,行处理反之
|
||||||
|
*/
|
||||||
|
|
||||||
|
function f1(matrix) {
|
||||||
|
const m = matrix.length;
|
||||||
|
const n = matrix[0].length;
|
||||||
|
const rowFlag = new Array(m).fill(false); // 行标记
|
||||||
|
const colFlag = new Array(n).fill(false); // 列标记
|
||||||
|
|
||||||
|
// 第一次遍历,记录哪些行和列需要置零
|
||||||
|
for (let i = 0; i < m; i++) {
|
||||||
|
for (let j = 0; j < n; j++) {
|
||||||
|
if (matrix[i][j] === 0) {
|
||||||
|
rowFlag[i] = true;
|
||||||
|
colFlag[j] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二次遍历,根据标记设置矩阵元素为0
|
||||||
|
for (let i = 0; i < m; i++) {
|
||||||
|
for (let j = 0; j < n; j++) {
|
||||||
|
if (rowFlag[i] || colFlag[j]) {
|
||||||
|
matrix[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
利用第一行来标记哪些列应该处理为零,利用第一列来标记哪些行应该处理为零,遍历除第一行和第一列的所有元素,假设matrix[i][j]===0,那么就在
|
||||||
|
matrix[0][j] = 0, matrix[i][0] = 0, 最后遍历所有的元素,如果它所在的行和列,只要其中之一等于零,那么就设置它为零,由于利用第一列和第一
|
||||||
|
行来存储信息,所以在收集信息之前需要判断第一行和第一列是否原本就有零,如果就记录,最后在上面所有步骤都处理完成之后通过记录的信息设置第一行
|
||||||
|
和第一列是否需要设置为零
|
||||||
|
*/
|
||||||
|
|
||||||
|
function f2(matrix) {
|
||||||
|
let rowFlag = false; // 标记矩阵的第一行是否原本就有零
|
||||||
|
let colFlag = false; // 标记矩阵的第一列是否原本就有零
|
||||||
|
const m = matrix.length;
|
||||||
|
const n = matrix[0].length;
|
||||||
|
|
||||||
|
// 如果第一行中某个元素是零,就标记为true
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
if (matrix[0][i] === 0) {
|
||||||
|
rowFlag = true;
|
||||||
|
break; // 找到就可以退出了,不需要继续循环
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果第一列中某个元素是零,就标记为true
|
||||||
|
for (let i = 0; i < m; i++) {
|
||||||
|
if (matrix[i][0] === 0) {
|
||||||
|
colFlag = true;
|
||||||
|
break; // 找到就可以退出了,不需要继续循环
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历剩余的元素,如果是零,就在第一行和第一列标记为零
|
||||||
|
for (let i = 1; i < m; i++) {
|
||||||
|
for (let j = 1; j < n; j++) {
|
||||||
|
if (matrix[i][j] === 0) {
|
||||||
|
matrix[0][j] = 0;
|
||||||
|
matrix[i][0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历第一行,如果发现当前的值为零,就设置其列为零
|
||||||
|
for (let i = 1; i < n; i++) { // 从1开始,跳过matrix[0][i]
|
||||||
|
if (matrix[0][i] === 0) {
|
||||||
|
for (let j = 0; j < m; j++) { // 设置i列的所有元素为零
|
||||||
|
matrix[j][i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历第一列,如果发现当前的值为零,就设置其行为零
|
||||||
|
for (let i = 1; i < m; i++) { // 从1开始,跳过matrix[i][0]
|
||||||
|
if (matrix[i][0] === 0) {
|
||||||
|
for (let j = 0; j < n; j++) { // 设置i行的所有元素为零
|
||||||
|
matrix[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过rowFlag和colFlag来判断第一列和第一行是否需要全部设置为零
|
||||||
|
if (rowFlag) {
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
matrix[0][i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colFlag) {
|
||||||
|
for (let i = 0; i < m; i++) {
|
||||||
|
matrix[i][0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user