class Solution {
// 方法 isValidSudoku 接收一个字符二维数组 board,表示数独棋盘,返回是否有效
public boolean isValidSudoku(char[][] board) {
// 创建三个二维数组来记录每一行、列和子框中数字的出现次数
int[][] rows = new int[9][9]; // 行记录
int[][] columns = new int[9][9]; // 列记录
int[][][] subboxes = new int[3][3][9]; // 子框记录
// 遍历整个棋盘
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char c = board[i][j]; // 当前单元格的字符
// 如果单元格不是空格(即不是 '.')
if (c != '.') {
// 计算当前数字的索引(1-9 映射到 0-8) 如果重复相同的数映射到同一个位置会不断+1,如果重复就会大于1
int index = c - '0' - 1;
// 在行、列和子框中更新当前数字的出现次数
rows[i][index]++; // 增加行的计数
columns[j][index]++; // 增加列的计数
subboxes[i / 3][j / 3][index]++; // 增加子框的计数
// 如果某个位置的计数超过 1,说明出现重复,返回 false
if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[i / 3][j / 3][index] > 1) {
return false; // 数独无效
}
}
}
}
// 如果循环结束,说明没有发现重复,返回 true
return true; // 数独有效
}
}
class Solution {
// // 方法 spiralOrder 接收一个二维整数数组 matrix,返回矩阵的螺旋顺序遍历结果
public List<Integer> spiralOrder(int[][] matrix) {
// 获取矩阵的行数
int m = matrix.length;
// 获取矩阵的列数
int n = matrix[0].length;
// 定义四个边界
// 上边界
int up = 0;
// 左边界
int left = 0;
// 右边界
int right = n - 1;
// 下边界
int down = m - 1;
// 存储结果的列表
List<Integer> result = new ArrayList<>();
// 使用循环遍历,直到所有元素都被访问
while(true) {
// 从左到右遍历上边界
for (int i = left; i <= right; i++) {
// 添加当前元素到结果列表中
result.add(matrix[up][i]);
}
// 更新上边界,检查是否已超出下边界
if (++up > down) {
// 如果上边界超过下边界,结束循环
break;
}
// 从上到下遍历右边界
for (int i = up; i <= down; i++) {
result.add(matrix[i][right]); // 添加当前元素到结果列表中
}
// 更新右边界,检查是否已超出左边界
if (--right < left) {
break; // 如果右边界超过左边界,结束循环
}
// 从右到左遍历下边界
for (int i = right; i >= left; i--) {
result.add(matrix[down][i]); // 添加当前元素到结果列表中
}
// 更新下边界,检查是否已超出上边界
if (--down < up) {
break; // 如果下边界超过上边界,结束循环
}
// 从下到上遍历左边界
for (int i = down; i >= up; i--) {
result.add(matrix[i][left]); // 添加当前元素到结果列表中
}
// 更新左边界,检查是否已超出右边界
if (++left > right) {
break; // 如果左边界超过右边界,结束循环
}
}
// 返回螺旋顺序遍历的结果
return result;
}
}
class Solution {
// 方法 rotate 接收一个二维整数数组 matrix,表示要旋转的矩阵
public void rotate(int[][] matrix) {
// 获取矩阵的行数 m
int m = matrix.length;
// 获取矩阵的列数 n
int n = matrix[0].length;
// 创建一个临时矩阵,用于存储原矩阵的值
int[][] temp = new int[m][];
for (int i = 0; i < m; i++) {
// 深拷贝原矩阵的每一行,以防旋转时修改原矩阵的值
temp[i] = matrix[i].clone(); // 使用 clone() 方法进行深拷贝
}
// 遍历临时矩阵,将值重新赋值到原矩阵中的适当位置,完成顺时针旋转
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 根据旋转公式,把 temp[i][j] 放到 matrix[j][n - 1 - i]
matrix[j][n - 1 - i] = temp[i][j];
}
}
}
}
class Solution {
// 方法 setZeroes 接收一个二维整数数组 matrix,表示要处理的矩阵
public void setZeroes(int[][] matrix) {
int m = matrix.length; // 获取矩阵的行数
int n = matrix[0].length; // 获取矩阵的列数
// 创建两个标记数组,用于记录需要置零的行和列
boolean[] row = new boolean[m]; // 行标记位
boolean[] col = new boolean[n]; // 列标记位
// 第一次遍历整个矩阵,查找值为 0 的元素
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) { // 如果当前元素为 0
row[i] = true; // 将对应的行标记为 true
col[j] = true; // 将对应的列标记为 true
}
}
}
// 第二次遍历,根据标记修改矩阵中的元素
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 如果该行或该列需要置为 0,则将当前元素设置为 0
if (row[i] || col[j]) {
matrix[i][j] = 0; // 设置当前元素为 0
}
}
}
}
}
class Solution {
// 方法 gameOfLife 接收一个二维整数数组 board,表示细胞的当前状态
public void gameOfLife(int[][] board) {
// 创建一个数组来表示邻居的位置变化,邻居可以在横向、纵向和对角线
int[] neighbors = {0, 1, -1};
int rows = board.length; // 获取行数
int cols = board[0].length; // 获取列数
// 创建一个复制数组 copyBoard,用于存储当前状态
int[][] copyBoard = new int[rows][cols];
// 从原数组复制一份到 copyBoard 中
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
copyBoard[row][col] = board[row][col]; // 深拷贝细胞状态
}
}
// 遍历面板中的每一个细胞
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
// 统计当前细胞八个相邻细胞中的活细胞数量
int liveNeighbors = 0;
// 检查当前细胞的所有邻居
for (int i = 0; i < 3; i++) { // 遍历邻居的行偏移
for (int j = 0; j < 3; j++) { // 遍历邻居的列偏移
// 排除当前细胞自身
if (!(neighbors[i] == 0 && neighbors[j] == 0)) {
int r = (row + neighbors[i]); // 计算邻居的行坐标
int c = (col + neighbors[j]); // 计算邻居的列坐标
// 检查邻居是否在矩阵内,并且是活细胞
if ((r < rows && r >= 0) && (c < cols && c >= 0) && (copyBoard[r][c] == 1)) {
liveNeighbors += 1; // 统计活细胞数量
}
}
}
}
// 应用生命游戏规则:
// 规则 1 或 规则 3:活细胞与少于 2 个或多于 3 个活邻居则死亡
if ((copyBoard[row][col] == 1) && (liveNeighbors < 2 || liveNeighbors > 3)) {
board[row][col] = 0; // 死亡
}
// 规则 4:死细胞有正好 3 个活邻居则复活
if (copyBoard[row][col] == 0 && liveNeighbors == 3) {
board[row][col] = 1; // 复活
}
}
}
}
}