一 LC73.矩阵置零
题目要求:
给定一个
m x n
的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
思路分析:
首先我们需要记录矩阵中所有含有0的行和列。为了避免在修改过程中影响其他要修改的位置,我们可以使用矩阵的第一行和第一列作为标记。但这样会导致原数组的第一行和第一列被修改,无法记录它们是否原本包含 0。因此我们需要额外使用两个标记变量分别记录第一行和第一列是否原本包含 0。标记完成后,我们根据记录的标记来将对应的行和列的所有元素置为0,再根据标记变量处理第一行和第一列。
完整代码示例:
class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
// 记录是否需要将第一行和第一列置为0
boolean firstRowZero = false;
boolean firstColZero = false;
// 检查第一行是否包含0
for (int j = 0; j < n; j++) {
if (matrix[0][j] == 0) {
firstRowZero = true;
break;
}
}
// 检查第一列是否包含0
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) {
firstColZero = true;
break;
}
}
// 使用第一行和第一列作为标记来记录其他行和列
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][j] == 0) {
matrix[i][0] = 0; // 标记所在列
matrix[0][j] = 0; // 标记所在行
}
}
}
// 根据标记将对应行和列设置为0
for (int i = 1; i < m; i++) {
if (matrix[i][0] == 0) {
for (int j = 0; j < n; j++) {
matrix[i][j] = 0;
}
}
}
for (int j = 1; j < n; j++) {
if (matrix[0][j] == 0) {
for (int i = 0; i < m; i++) {
matrix[i][j] = 0;
}
}
}
// 处理第一行
if (firstRowZero) {
for (int j = 0; j < n; j++) {
matrix[0][j] = 0;
}
}
// 处理第一列
if (firstColZero) {
for (int i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
}
}
二 LC54.螺旋矩阵
题目要求:
给你一个
m
行n
列的矩阵matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
思路分析:
我们首先定义矩阵的四个边界,初始时为上边界 top = 0
、下边界 bottom =
matrix.length - 1、左边界 left
= 0、右边界 right =
matrix[0].length - 1。
之后我们从左到右遍历上边界的所有元素,然后更新上边界。从上到下遍历右边界的所有元素,然后更新右边界。从右到左遍历下边界的所有元素(如果还有下边界),然后更新下边界。从下到上遍历左边界的所有元素(如果还有左边界),然后更新左边界。循环往复,直到所有边界相遇,表示遍历结束,退出循环。
完整代码示例:
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> result = new ArrayList<>();
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return result;
}
int top = 0;
int bottom = matrix.length - 1;
int left = 0;
int right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
// 从左到右遍历上边界
for (int j = left; j <= right; j++) {
result.add(matrix[top][j]);
}
top++;
// 从上到下遍历右边界
for (int i = top; i <= bottom; i++) {
result.add(matrix[i][right]);
}
right--;
if (top <= bottom) {
// 从右到左遍历下边界
for (int j = right; j >= left; j--) {
result.add(matrix[bottom][j]);
}
bottom--;
}
if (left <= right) {
// 从下到上遍历左边界
for (int i = bottom; i >= top; i--) {
result.add(matrix[i][left]);
}
left++;
}
}
return result;
}
}
三 LC48.旋转图像
题目要求:
给定一个 n × n 的二维矩阵
matrix
表示一个图像。请你将图像顺时针旋转 90 度。你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
思路分析:
不借助另一个矩阵直接旋转比较难以实现,但是我们可以观察旋转前后的图形规律,不难看出,我们可以先交换矩阵中的对称元素,即将第 iii 行第 jjj 列的元素与第 jjj 行第 iii 列的元素交换。
再反转每一行元素,即可完成旋转。
体现在代码上,就是遍历矩阵的上三角部分(包括对角线),将第 iii 行第 jjj 列的元素与第 jjj 行第 iii 列的元素交换,完成后,再遍历每一行,将每行的元素从两端向中间交换,这样每一行就变成了旋转后的样子。因为我们需要遍历每个元素进行交换和反转。所以时间复杂度为O(n^2)。
完整代码示例:
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// Step 1: 交换对应位置元素
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// Step 2: 按行进行反转
for (int i = 0; i < n; i++) {
for (int j = 0; j < n / 2; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[i][n - j - 1];
matrix[i][n - j - 1] = temp;
}
}
}
}