feat: matrix leetcode 36,48,54,73,289

This commit is contained in:
LouisFonda 2025-04-04 23:27:40 +08:00
parent eb9dee4335
commit 0d078c09b4
Signed by: yigencong
GPG Key ID: 29CE877CED00E966
5 changed files with 379 additions and 0 deletions

View 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位更新状态为新的细胞状态
}
}
}

View 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;
}

View 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--;
}
}
}

View 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;
}

View 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;
}
}
}