题目描述:
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,
例如,如果输入如下4 X 4矩阵:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
测试用例:
矩阵中有多行多列、矩阵中只有一行或者一列、数组中只有一列、数组中只有一行一列。(并没有考虑矩阵为空的情况)
解题思路:
1)^-^- 规律:每次圈的起始点都是(0,0)(1,1)(start,start)行列的数字相等
^-^- 一个矩阵能划分为多少个圈:找规律
对于一个5*5的矩阵,最后一圈只有一个数字,对应的坐标为(2,2)。5>2*2
对于一个6*6的矩阵,最后一圈只有一个数字,对应的坐标为(2,2)。6>2*2
于是可以得出。让循环继续的条件是 columns>startX*2 并且 rows>startY*2
^-^- 可以把打印一圈分为四步:第一步,从左到右打印一行;第二步,从上到下打印一列;第三步,从右到左打印一行;第四步,从下到上打印一列。每一步根据起始坐标和终止坐标用循环打印出一行或者一列。
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
if(matrix.size()==0) //
return result;
int start = 0; //标志着第几圈
int rows = matrix.size();
int cols = matrix[0].size();
while(rows>start*2 && cols>start*2){
printMatrixInCircle( matrix,rows,cols,start);
start++;
}
return result;
}
void printMatrixInCircle(vector<vector<int> > matrix,int rows,int cols,int start){
int endCol = cols-1-start;
int endRow = rows-1-start;
//第一步:打印第一行(一定会打印)
for(int col=start; col<=endCol; col++){
result.push_back(matrix[start][col]);
}
//第二步:若行数大于等于二(即多于一行时),则会打印。即endRow-start>0
if(endRow-start>0){
for(int row=start+1; row<=endRow; row++)
result.push_back(matrix[row][endCol]);
}
//第三步:至少两行两列
if(endRow-start>0 && endCol-start>0){ //
for(int col=endCol-1; col>=start; col--)
result.push_back(matrix[endRow][col]);
}
//第三步:至少三行两列
if(endRow-start>1 && endCol-start>0){
for(int row=endRow-1; row>start; row--)
result.push_back(matrix[row][start]);
}
}
private:
vector<int> result;
};
2)int
circle=((row<collor?row:collor)-1)/2+1;
//圈数
3)定义四个关键变量,表示左上和右下的打印范围,限定一个圈。每次循环后缩小一圈
/*
思想,用左上和右下的坐标定位出一次要旋转打印的数据,一次旋转打印结束后,往对角分别前进和后退一个单位。
提交代码时,主要的问题出在没有控制好后两个for循环,需要加入条件判断,防止出现单行或者单列的情况。
*/
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
int row = matrix.size();
int col = matrix[0].size();
vector<int> res;
// 输入的二维数组非法,返回空的数组
if (row == 0 || col == 0) return res;
// 定义四个关键变量,表示左上和右下的打印范围
int left = 0, top = 0, right = col - 1, bottom = row - 1;
while (left <= right && top <= bottom) //至少有一个元素时
{
// left to right 一定会打印
for (int i = left; i <= right; ++i) res.push_back(matrix[top][i]);
// top to bottom 行数多于1行才会打印 here 只有一行时不会进入for循环,因此该处无需判断
for (int i = top + 1; i <= bottom; ++i) res.push_back(matrix[i][right]);
// right to left //至少两行两列时,才会打印 top != bottom限制至少两行 for循环限制right-1>=left,即至少两行
if (top != bottom)
for (int i = right - 1; i >= left; --i) res.push_back(matrix[bottom][i]);
// bottom to top //至少三行两列 left != right限制两列 bottom - 1> top 至少三列
if (left != right)
for (int i = bottom - 1; i > top; --i) res.push_back(matrix[i][left]);
left++,top++,right--,bottom--; //缩小一圈
}
return res;
}
};
4)顺着走,即向右->向下->向左->向上,一共要走(长*宽)步。遇到边界就改变方向,当向上碰到顶的时候,四个边界都缩小。思路简单,一个循环即可!
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
vector<int> ret;
if(matrix.empty())return ret;
int x,y,cnt=matrix[0].size()*matrix.size(); //一共需要打印的个数
//右rEdge 下dEdge 左lEdge 上uEdge
int rEdge=matrix[0].size()-1,dEdge=matrix.size()-1,lEdge=0,uEdge=0;
//bool first=true;
for(x=0,y=0;cnt>0;cnt--){ //从(0,0)开始
ret.push_back(matrix[x][y]);
//go right
if(x==uEdge){ //上边界
if(y<rEdge) //小于右边界时,向右移动。y++
y++;
else if(y==rEdge) //到达右边界,向下移动
x++;
continue; //不会再判断后面的if了
}
//down
if(y==rEdge){
if(x<dEdge)
x++;
else if(x==dEdge){
y--;
}
continue; //不会再判断后面的if了
}
//left
if(x==dEdge){
if(y>lEdge)
y--;
else if(y==lEdge){
x--;
}
continue; //不会再判断后面的if了
}
//up
if(y==lEdge){
if(x>uEdge+1)
x--;
else if( x==uEdge+1){ //到达一圈的最后一个点
y++;
lEdge++;
uEdge++;
rEdge--;
dEdge--;
}
continue;
}
//;3
}
return ret;
}
};