本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。
1.题目1:59. 螺旋矩阵 II
1.1.解法1:模拟
本题的重点还是像之前的“704.二分查找”,坚持循环不变量原则,即在本题中遍历每条边时,坚持相同的原则。
如下是一个示例,即n=5,我们考虑根据圈数和边数来进行遍历:
由外圈到内圈,而边的方向则为:①从左到右、②从上到下、③从右到左、④从下到上。
(1)从外圈到内圈:引入start变量作为“转圈”开始的位置,初始时start的值为0;第二圈时,start的值为1。
(2)边①②③④:这里在遍历每条边时,始终坚持“左闭右开”,也就是遍历①时1、2、3、4,遍历②时5、6、7、8,遍历③时9、10、11、12,遍历④时13、14、15、16。通过offset来控制每条边遍历结束的位置(n-offset),相应第二圈时,offset的值+1。
(3)当n为奇数时,中间会剩下一个数,如图中“25”,我们最后对中间数进行单独赋值。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>>nums(n, vector<int>(n, 0));
int loop = n / 2; // 要旋转的圈数
int start = 0; // 起始位置
int offset = 1; // 控制每一条边遍历的长度,每次循环右边界收缩一位
int count = 1; // 用于赋值
while (loop--) {
int j = start, i = start;
// 以下四个for循环即旋转了一圈
// (1)从左向右
for (; j < n - offset; j++) {
nums[i][j] = count++;
}
// (2)从上向下
for (; i < n - offset; i++) {
nums[i][j] = count++;
}
// (3)从右向左
for (; j > start; j--) {
nums[i][j] = count++;
}
// (4)从下向上
for (; i > start; i--) {
nums[i][j] = count++;
}
start++; // 第二圈开始的时,起始位置要加1
offset += 1; // 控制每一圈里每一条边遍历的长度
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2 == 1) nums[n / 2][n / 2] = count;
return nums;
}
};
● 时间复杂度:\(O(n^2)\)。
● 空间复杂度:\(O(1)\)。
2.题目2:54.螺旋矩阵
类似于59.螺旋矩阵II,但本题矩阵行列不一定相等,且要求顺时针方向输出指定的矩阵。
2.1.解法1:模拟
思路上和59.螺旋矩阵II相似,都是:由外圈到内圈,而边的方向则为:①从左到右、②从上到下、③从右到左、④从下到上。
不过需要注意一点,因为行数列数不相等的情况下:
1.旋转的圈数应为:min(列数,行数) / 2。
2.当min(列数,行数)为奇数时:
min(列数,行数) = 列数,即还剩余一个中间列没有被遍历到;
min(列数,行数) = 行数,即还剩余一个中间行没有被遍历到;
剩余的中间行或是中间列还需要单独去进行遍历,按照题意填充到目标数组中。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
vector<int>nums(m * n);
int start = 0;
int loop = min(m, n) / 2;
int count = 0;
int offset = 1;
int i, j;
while (loop --) {
i = start, j = start;
// (1)从左往右
for (; j < n - offset; j++) {
nums[count++] = matrix[i][j];
}
// (2)从上往下
for (; i < m - offset; i++) {
nums[count++] = matrix[i][j];
}
// (3)从右往左
for (; j > start; j--) {
nums[count++] = matrix[i][j];
}
// (4)从下往上
for (; i > start; i--) {
nums[count++] = matrix[i][j];
}
start++;
offset++;
}
int mid = min(m, n) / 2;
if (min(m, n) % 2) {
if (m > n) { // 剩下一个中间列
for (int i = mid; i < mid + m - n + 1; i++) {
nums[count++] = matrix[i][mid];
}
}
else { // 剩下一个中间行
for (int i = mid; i < mid + n - m + 1; i++) {
nums[count++] = matrix[mid][i];
}
}
}
return nums;
}
};
● 时间复杂度:\(O(n^2)\) 模拟遍历二维矩阵的时间。
● 空间复杂度:\(O(1)\)。
2.2.解法2:模拟(简洁)
这是力扣上某大佬的一种解法:
1.设定上下左右边界。
2.从左向右,第一行已经遍历完,便可以从中删除,相当于重新定义上边界。
3.如果重新定义的上边界与下边界交错,表示遍历结束,跳出循环,返回答案。
若不交错,继续向下、向左、向上遍历,操作步骤同1.2。
4.循环以上步骤,直至两边界交错,跳出循环,返回答案。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int>ans;
if (matrix.empty()) return ans;
int left = 0, right = matrix[0].size() - 1, top = 0, bottom = matrix.size() - 1;
while (true) {
// 1.从左向右
for (int i = left; i <= right; i++) {
ans.push_back(matrix[top][i]);
}
if (++top > bottom) break;
// 2.从上向下
for (int i = top; i <= bottom; i++) {
ans.push_back(matrix[i][right]);
}
if (--right < left) break;
// 3.从右向左
for (int i = right; i >= left; i--) {
ans.push_back(matrix[bottom][i]);
}
if (--bottom < top) break;
// 4.从下向上
for (int i = bottom; i >= top; i--) {
ans.push_back(matrix[i][left]);
}
if (++left > right) break;
}
return ans;
}
};
3.题目3:LCR 146. 螺旋遍历二维数组
这题的解法同54。
3.1.解法1:模拟
class Solution {
public:
vector<int> spiralArray(vector<vector<int>>& array) {
if (array.size() == 0 || array[0].size() == 0) return {};
int m = array.size(), n = array[0].size();
vector<int>nums(m * n);
int loop = min(m, n) / 2;
int start = 0;
int offset = 1;
int count = 0;
int i, j;
while (loop --) {
i = start, j = start;
for (; j < n - offset; j++) {
nums[count++] = array[i][j];
}
for (; i < m - offset; i++) {
nums[count++] = array[i][j];
}
for (; j > start; j--) {
nums[count++] = array[i][j];
}
for (; i > start; i--) {
nums[count++] = array[i][j];
}
start++;
offset++;
}
int mid = min(m, n) / 2;
if (min(m, n) % 2) {
if (m > n) {
for (int i = mid; i < mid + m - n + 1; i++) {
nums[count++] = array[i][mid];
}
}
else {
for (int i = mid; i < mid + n - m + 1; i++) {
nums[count++] = array[mid][i];
}
}
}
return nums;
}
};
● 时间复杂度:\(O(n^2)\) 模拟遍历二维矩阵的时间。
● 空间复杂度:\(O(1)\)。