给定一个正整数 `n`,生成一个包含 1 到 `n^2` 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
思路:
- > 区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。
- 循环矩阵就是转一个圈,遍历每个圈的上下左右四条边;
- 根据定义的区间如左闭右开作为每条边的循环条件进行元素赋值;
- n/2的值就是要转几圈,但n为奇数、偶数时不一样, 奇数时通过n%2来判断是否有剩余一个元素;
- 遍历内圈时,每条边:更新起始位置++;控制终止位置的变量offset++;
关于二维数组:
1. 理解二维数组的定义:`vector<vector<int>> res(n, vector<int>(n, 0))`;//n 代表外围数组的元素个数,也就是行数;`vector<int>(n, 0)`代表列数和初始值
2. 二维数组的输出,j < res[0].size()获取列数
3. **二维数组在内存的空间地址是连续的么?**
**二维数组在内存中不是 `3*4` 的连续地址空间,而是四条连续的地址空间组成**
代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
//给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int startX = 0;
int startY = 0;
int offset = 1;
int count = 1; // 用来给矩阵中每一个空格赋值
int loop = n / 2; 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
int i , j;//矩阵的位置
while (loop --)
{
i = startX;
j = startY;
//上
for (j = startY; j < n - offset; j++) {
res[i][j] = count++;
}
//右
for (i = startX; i < n - offset; i++) {
res[i][j] = count++;
}
//下
for (; j > startY; j--) {
res[i][j] = count++;
}
//左
for (; i > startX; i--) {
res[i][j] = count++;
}
第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startX++; startY++;
// offset 控制每一圈里每一条边遍历的长度
offset++;
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2) {
res[mid][mid] = count++;
}
return res;
}
};
int main() {
Solution solution;
vector<vector<int>> res = solution.generateMatrix(5);
for (int i = 0; i < res.size(); i++) {
for (int j = 0; j < res[0].size(); j++) {
cout << res[i][j] << " ";
}
cout << endl;
}
system("pause");
return 0;
}
//输出
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
关于螺旋矩阵
描述:给你一个 `m` 行 `n` 列的矩阵 `matrix` ,请按照 **顺时针螺旋顺序** ,返回矩阵中的所有元素。
思考:
对于不规则矩阵,应该如何控制遍历次数,遍历过后并对剩余元素做赋值?结合已加次数`count`与矩阵元素`nums`比较是否继续循环
难点就在于是否添加完了所有参数进`vector<int> res`?有时候添加多了。加入已加次数`count`<`nums`这个条件
不断修修改改终于提交成功.......
#include<vector>
#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int startX = 0;
int startY = 0;
int offset = 1;
int count = 0;//记录遍历元素个数
int row = matrix.size();//行数
int columns = matrix[0].size();//列数
int loop = max(row, columns)/2;
int nums = row * columns;//个数
vector<int> res;
int i, j;
cout << "nums: " << nums << " loop = " << loop << " row = " << row << " columns = " << columns << endl;
while (loop-- && count < nums) {
i = startX;
j = startY;
cout << " count = " << count << endl;
if (row == 1 || columns == 1) {//针对
if (row == 1)
{
for (int j = 0; j < columns; j++) {
res.push_back(matrix[0][j]);
}
return res;
}
else {
for (int i = 0; i < row; i++) {
res.push_back(matrix[i][0]);
}
return res;
}
}
//上
for (j = startY; j < columns - offset; j++, count++) {
cout << " 上:i = " << i << " j = " << j << " ";
res.push_back(matrix[i][j]);
}
cout << endl;
//右
for (i = startX; i < row - offset; i++, count++) {
cout << " 右:i = " << i << " j = " << j << " ";
res.push_back(matrix[i][j]);
}
cout << endl;
//下
for (; j > startY && count < nums; j--, count++) {
cout << " 下:i = " << i << " j = " << j << " ";
res.push_back(matrix[i][j]);
}
cout << endl;
//左
for (; i > startX && count < nums; i--, count++) {
cout << " 左:i = " << i << " j = " << j << " ";
res.push_back(matrix[i][j]);
}
cout << endl;
offset++;
startX++;
startY++;
}
if (row == columns && max(row, columns)%2 != 0 && count != nums) {
cout << " 剩余元素 :" << matrix[max(row, columns) / 2][max(row, columns) / 2] << endl;
res.push_back(matrix[max(row, columns) /2][max(row, columns) / 2]);
}
return res;
}
};
int main() {
vector<vector<int>> test1 = { {1, 2, 3},{4, 5, 6},{7, 8, 9} };
vector<vector<int>> test2 = { {1, 2, 3, 4},{5,6,7,8},{9,10,11,12} };//,{13,14,15,16}
vector<vector<int>> test3 = { {6,9,7}};//,{13,14,15,16}
vector<vector<int>> test4 = { {2,3,4},{5,6,7},{8,9,10},{11,12,13},{14,15,16} };
vector<vector<int>> test5 = { {1, 2, 3, 4,5,6,7,8,9,10},{11,12,13,14,15,16,17,18,19,20} };
vector<vector<int>> test6 = { {1, 2, 3, 4,5},{6,7,8,9,10 }, { 11,12,13,14,15} };
Solution solution;
vector<int> res = solution.spiralOrder(test6);
for (int i = 0; i < res.size(); i++) {
cout << res[i] << " ";
}
system("pause");
return 0;
}
别人的方法:
这里的方法不需要记录已经走过的路径,所以执行用时和内存消耗都相对较小
- 1. 首先设定上下左右边界
- 2. 其次向右移动到最右,此时第一行因为已经使用过了,可以将其从图中删去,体现在代码中就是重新定义上边界
- 3. 判断若重新定义后,上下边界交错,表明螺旋矩阵遍历结束,跳出循环,返回答案
- 4. 若上下边界不交错,则遍历还未结束,接着向下向左向上移动,操作过程与第一,二步同理
- 5. 不断循环以上步骤,直到某两条边界交错,跳出循环,返回答案
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector <int> ans;
if(matrix.empty()) return ans; //若数组为空,直接返回答案
int u = 0; //赋值上下左右边界
int d = matrix.size() - 1;
int l = 0;
int r = matrix[0].size() - 1;
while(true)
{
for(int i = l; i <= r; ++i) ans.push_back(matrix[u][i]); //向右移动直到最右
if(++ u > d) break; //重新设定上边界,若上边界大于下边界,则遍历遍历完成,下同
for(int i = u; i <= d; ++i) ans.push_back(matrix[i][r]); //向下
if(-- r < l) break; //重新设定有边界
for(int i = r; i >= l; --i) ans.push_back(matrix[d][i]); //向左
if(-- d < u) break; //重新设定下边界
for(int i = d; i >= u; --i) ans.push_back(matrix[i][l]); //向上
if(++ l > r) break; //重新设定左边界
}
return ans;
}
};