目录
以下摘自leetcode Top100精选题目-矩阵篇![](https://img-blog.csdnimg.cn/direct/13e4af8aafba4c689106ccec1658b37e.webp)
矩阵置零
给定一个 m x n
的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
示例:
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
Solution:
先遍历矩阵,记录下需要置零的行和列,再遍历一遍矩阵,根据记录的信息来决定哪些元素需要置零。这种方法避免了重复遍历矩阵中的每个元素来检查其行或列是否需要置零。
public void setZeroes(int[][] matrix) {
int m = matrix.length; // 矩阵的行数
int n = matrix[0].length; // 矩阵的列数
// 使用布尔数组标记哪些行和列需要置零
boolean[] rowFlags = new boolean[m];
boolean[] colFlags = new boolean[n];
// 遍历矩阵,标记需要置零的行和列
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
rowFlags[i] = true;
colFlags[j] = true;
}
}
}
// 根据标记的信息,将对应行和列置零
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (rowFlags[i] || colFlags[j]) {
matrix[i][j] = 0;
}
}
}
}
先通过两个布尔数组rowFlags
和colFlags
来分别标记哪些行和列需要被置零。在第一遍遍历中,如果发现某个元素为0,就将其所在的行和列对应的标记设为true
。在第二遍遍历时,检查每个元素所在行和列的标记,如果任一标记为true
,则将该元素置为0。
螺旋矩阵
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
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 rows = matrix.length, columns = matrix[0].length;
int top = 0, bottom = rows - 1, left = 0, right = columns - 1;
while (top <= bottom && left <= right) {
// 从左到右打印顶部一行
for (int i = left; i <= right; i++) {
result.add(matrix[top][i]);
}
top++; // 缩小顶部边界
// 从上到下打印右侧一列
for (int i = top; i <= bottom; i++) {
result.add(matrix[i][right]);
}
right--; // 缩小右侧边界
if (top <= bottom) { // 防止只有单行或单列时重复打印
// 从右到左打印底部一行
for (int i = right; i >= left; i--) {
result.add(matrix[bottom][i]);
}
bottom--; // 缩小底部边界
}
if (left <= right) { // 同样防止只有单行或单列时重复打印
// 从下到上打印左侧一列
for (int i = bottom; i >= top; i--) {
result.add(matrix[i][left]);
}
left++; // 缩小左侧边界
}
}
return result;
}
先检查输入矩阵是否为空或无元素,初始化四个边界指针。进入一个循环,只要顶部边界不大于底部边界且左边界不大于右边界,就继续执行。在循环内部,按照顺时针顺序遍历当前层的四个边,并在遍历完每一侧后相应地调整边界。当所有层遍历完毕,返回结果列表,其中包含矩阵中所有元素的顺时针螺旋顺序。
旋转图像
给定一个 n × n 的二维矩阵 matrix
表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
Solution:
要原地旋转一个n×n的二维矩阵90度,可以遵循以下步骤:
- 按照层来进行操作,首先处理最外层(即第一行到最后一行,但不包括第一列和最后一列)。
- 对于每层中的每个元素,将其与它所要交换到的位置的元素进行交换。具体来说,假设当前处理的元素坐标为
(x, y)
,那么它将被交换到(y, n-x-1)
位置,其中n
是矩阵的边长。
public void rotate(int[][] matrix) {
int n = matrix.length;
// 层数,最外层是0层,向内依次递增
for (int layer = 0; layer < n / 2; layer++) {
// 每一层需要交换的元素个数,注意排除边界
int len = n - 2 * layer - 1;
for (int i = 0; i < len; i++) {
// 保存左上角的元素,用于后续的交换
int temp = matrix[layer][layer + i];
// 左上 -> 右上
matrix[layer][layer + i] = matrix[n - 1 - layer - i][layer];
// 右上 -> 右下
matrix[n - 1 - layer - i][layer] = matrix[n - 1 - layer][n - 1 - layer - i];
// 右下 -> 左下
matrix[n - 1 - layer][n - 1 - layer - i] = matrix[layer + i][n - 1 - layer];
// 左下 -> 左上
matrix[layer + i][n - 1 - layer] = temp;
}
}
}
先计算出需要交换的层数(矩阵半径),然后对于每一层,计算出需要交换的元素个数,并执行旋转交换。通过这种方式,矩阵可以在原地完成90度的顺时针旋转。
搜索二维矩阵II
编写一个高效的算法来搜索 m x n
矩阵 matrix
中的一个目标值 target
。该矩阵具有以下特性:
- 每行的元素从左到右升序排列。
- 每列的元素从上到下升序排列
示例:
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true
Solution:
在有序的二维矩阵中搜索目标值,可以利用矩阵的有序特性,从矩阵的右上角或左下角开始搜索,这样每次比较都可以排除一行或一列。
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return false;
}
int rows = matrix.length;
int cols = matrix[0].length;
int row = 0; // 起始行
int col = cols - 1; // 起始列(右上角)
while (row < rows && col >= 0) {
if (matrix[row][col] == target) {
return true; // 找到目标值
} else if (matrix[row][col] < target) {
row++; // 目标值更大,移动到下一行
} else {
col--; // 目标值更小,移动到左一列
}
}
return false; // 没有找到目标值
}
先检查矩阵是否为空或无列,初始化行和列的指针,从矩阵的右上角开始。在循环中,如果找到了目标值,直接返回true
。如果当前元素小于目标值,则向下移动到下一行(因为同一列的元素从上到下是递增的)。如果当前元素大于目标值,则向左移动到前一列(因为同一行的元素从左到右是递增的)。如果循环结束还没有找到目标值,则返回false
。