模拟法
题一:
题目描述:
力扣链接🔗
题目分析:
而求解本题依然是要坚持循环不变量原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
由外向内一圈一圈这么画下去。
可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人。
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开又闭的原则,这样这一圈才能按照统一的规则画下来。
那么我按照左闭右开的原则,来画一圈,大家看一下:
这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。
这也是坚持了每条边左闭右开的原则。
代码:
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int mid = n / 2; // 表格中间的数字,例如:n为5,此时中心就为[2,2]
int count = 1; // 开始遍历的数字
int offset = 1; // 偏移量
int loop = n / 2; // 循环的圈树,例如:n为3,此时就只需要循环1圈
int startX = 0, startY = 0; // 开始遍历的位置
// 以下四个循环代表遍历一圈,此时都遵循左闭右开来遍历
while (loop > 0) {
int i = startY, j = startX;
// 遍历上边
for (; j < startX + n - offset; j++) {
res[i][j] = count++;
}
// 遍历右边
for (; i < startY + n - offset; i++) {
res[i][j] = count++;
}
// 遍历下边
for (; j > startX; j--) {
res[i][j] = count++;
}
// 遍历左边
for (; i > startY; i--) {
res[i][j] = count++;
}
// 将起始位置加一
startX++;
startY++;
// 将循环圈数减一
loop--;
// 将偏移量加二,因为边界多了2条
offset += 2;
}
// 如果n为奇数,将中心赋值
if (n % 2 == 1) {
res[mid][mid] = count;
}
return res;
}
}
题二:
题目描述:
力扣链接🔗
题目分析:
此时不是标准的正方形,此时使用层数来遍历会遇到许多判断,此时可以按层模拟,可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。
定义矩阵的第 k 层是到最近边界距离为 k 的所有顶点。例如,下图矩阵最外层元素都是第 1 层,次外层元素都是第 2 层,剩下的元素都是第 3 层。
[[1, 1, 1, 1, 1, 1, 1],
[1, 2, 2, 2, 2, 2, 1],
[1, 2, 3, 3, 3, 2, 1],
[1, 2, 2, 2, 2, 2, 1],
[1, 1, 1, 1, 1, 1, 1]]
按照如下路径遍历:
代码:
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new ArrayList<Integer>();
// 为空判断
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return list;
}
int rows = matrix.length, columns = matrix[0].length;
int top = 0, button = rows - 1, right = columns - 1, left = 0; // 代表上下左右
while (left <= right && top <= button) {
// 遍历上边
for (int column = left; column <= right; column++) {
list.add(matrix[top][column]);
}
// 遍历右边
for (int row = top + 1; row <= button; row++) {
list.add(matrix[row][right]);
}
// 注意此时没有判断等于,注意左下角和右上角的不同
if (left < right && top < button) {
for (int column = right - 1; column > left; column--) {
list.add(matrix[button][column]);
}
for (int row = button; row > top; row--) {
list.add(matrix[row][left]);
}
}
left++;
right--;
top++;
button--;
}
return list;
}
}
题三:
题目描述:
力扣链接🔗
题目分析:
此题和与上一题模拟方法一致,按照如下路径遍历。
代码:
class Solution {
public int[] spiralOrder(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return new int[]{};
}
List<Integer> list = new ArrayList<>();
int rows = matrix.length, columns = matrix[0].length; // 行列的数量
int top = 0, button = rows - 1, right = columns - 1, left = 0;
while (left <= right && top <= button) {
// 遍历上边
for (int column = left; column <= right; column++) {
list.add(matrix[top][column]);
}
// 遍历右边
for (int row = top + 1; row <= button; row++) {
list.add(matrix[row][right]);
}
if (left < right && top < button) {
// 遍历下边
for (int column = right - 1; column > left; column--) {
list.add(matrix[button][column]);
}
// 遍历左边
for (int row = button; row > top; row--) {
list.add(matrix[row][left]);
}
}
left++;
right--;
top++;
button--;
}
int[] ints = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
ints[i] = list.get(i);
}
return ints;
}
}