本章包括的题目有:
1.矩阵置零
思路解析:
有一种简单的思路是创建一个矩阵,标记每个0元素的位置,然后在原矩阵上根据标出来的位置将其行和列置为0。显然,这种思路的空间复杂度是 O(m n) 。当然,我们可以对其进行优化,创建两个数组,在遍历原矩阵的过程中,分别将遍历到的0位置的横纵坐标分别存入对应数组中,由于可能会有相同的横纵坐标,所以我们这里用HashSet去重,可以适当的优化时间效率。
代码实现:
java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
class Solution {
public void setZeroes(int[][] matrix) {
Set<Integer> line = new HashSet<>();
Set<Integer> row = new HashSet<>();
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if(matrix[i][j] == 0){
line.add(i);
row.add(j);
}
}
}
for(Integer l : line){
for (int i = 0; i < matrix[0].length; i++) {
matrix[l][i] = 0;
}
}
for(Integer r : row){
for (int i = 0; i < matrix.length; i++) {
matrix[i][r] = 0;
}
}
}
}
时间复杂度O(m*n)
空间复杂度O(m + n)
当然,我们也可以原地对其进行标记,得到空间复杂度为 O(1)的方法,可以先定义两个变量,看一下第一行和第一列是否需要被标记为0。然后遍历数组,若某个位置是0,则将其对应的行的第一个和列的第1个位置都标记为0,这样遍历完成之后,再通过第一行和第一列被标记为0的数据去调整整个数组。

如图所示,第一张为原数组,由于第一行有0,所以我们要用一个常量标记第一行,最终要全部置为0,然后将中间位置的0分别将其对应的行列的第一个位置标为0,这样在遍历行的时候,把行对应的所有列标记为0,遍历列的时候,把列对应的所有行标记为0,最后再看常量是否标记第一行和第一列,即可完成整个矩阵的置零操作。
2.螺旋矩阵
思路解析:
螺旋矩阵思路简单,但是代码的细节问题较多,笔者写的时候的思路是,先创建一个矩阵去表示当前位置的值是否被访问过。然后依次向左、向下、向右、向上循环,直到访问到边界,或者访问到被访问过的元素,依次访问完所有元素,即可得到答案。
代码实现:
java
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
ArrayList<Integer> ret = new ArrayList<>();
boolean[][] visited = new boolean[m][n];
int i = 0,j = 0;
while(m * n != ret.size()){
while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){
ret.add(matrix[i][j]);
visited[i][j] = true;
j++;
if(j >= n || visited[i][j]) {
j--;
i++;
break;
}
}
while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){
ret.add(matrix[i][j]);
visited[i][j] = true;
i++;
if(i >= m || visited[i][j]) {
i--;
j--;
break;
}
}
while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){
ret.add(matrix[i][j]);
visited[i][j] = true;
j--;
if(j < 0 || visited[i][j]) {
j++;
i--;
break;
}
}
while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){
ret.add(matrix[i][j]);
visited[i][j] = true;
i--;
if(i < 0 || visited[i][j]) {
i ++;
j ++;
break;
}
}
}
return ret;
}
}
但是这样写极容易出错,我们可以通过维护四个边界的方式,一步步缩小整个矩阵的搜索范围。维护四个边界:top, bottom, left, right,按顺序打印: 上行:从 left 到 right,然后 top++ ;右列:从 top 到 bottom,然后 right-- ;下行:从 right 到 left,然后 bottom-- ;左列:从 bottom 到 top,然后 left++
代码实现:
java
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
if (matrix.length == 0) return res;
int top = 0, bottom = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
for (int j = left; j <= right; j++) {
res.add(matrix[top][j]);
}
top++;
for (int i = top; i <= bottom; i++) {
res.add(matrix[i][right]);
}
right--;
if (top <= bottom) {
for (int j = right; j >= left; j--) {
res.add(matrix[bottom][j]);
}
bottom--;
}
if (left <= right) {
for (int i = bottom; i >= top; i--) {
res.add(matrix[i][left]);
}
left++;
}
}
return res;
}
}
3.旋转图像
思路解析:
我们可以将矩阵层层转置,通过四角轮换的方式

代码实现:
java
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
for (int i = 0; i < n / 2; i++) {
for (int j = i; j < n - 1 - i; j++) {
swap(i ,j, matrix);
}
}
}
private void swap(int i, int j, int[][] matrix) {
//[i][j], [j][len - 1 - i], [len - 1 - i][len - 1 - j], [len - 1 - j][i]
int n = matrix.length;
int temp = matrix[i][j];
matrix[i][j] = matrix[n - 1 - j][i];
matrix[n - 1 - j][i] = matrix[n - 1 - i][n - 1 - j];
matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i];
matrix[j][n - 1 - i] = temp;
}
}
时间复杂度O(n*n)
空间复杂度O(1)
拓展思路:
也可以通过转置加水平翻转的方式得到结果。先沿对角线将矩阵转置,然后将矩阵水平翻转,即可得到顺时针旋转的结果。
代码实现:
java
public void rotate(int[][] matrix) {
int n = matrix.length;
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;
}
}
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 - 1 - j];
matrix[i][n - 1 - j] = temp;
}
}
}
时间复杂度O(n*n)
空间复杂度O(1)
4.搜索二维矩阵
思路解析:
此题的关键在于我们要从右上角或者从左下角开始,这样的话,我们每次进行选择,就能排除掉一行或者一列。我们拿右上角举例,右上角如果往左走就是变小,往下走就是变大,可以通过对比当前值与目标值的大小,选择往下走或是往左走(类似二叉排序数)。
代码实现:
java
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0)
return false;
int m = matrix.length;
int n = matrix[0].length;
int i = 0, j = n - 1; // 从右上角开始
while (i < m && j >= 0) {
if (matrix[i][j] == target) {
return true;
} else if (matrix[i][j] > target) {
j--; // 当前值太大,排除当前列
} else {
i++; // 当前值太小,排除当前行
}
}
return false;
}
}
时间复杂度O(m + n)
空间复杂度O(1)
上一章:
LeetCode热题100(Java)(5)普通数组-CSDN博客
下一章:
链表(上)