【剑指offer】61.顺时针打印矩阵

总目录:

算法之旅导航目录

 

1.问题描述

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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]

 

2.问题分析

遍历的方向是有顺序的,顺时针意味着右、下、左、上,

延某个方向遍历时终止条件是到达矩阵边界或前方是已经走过的坐标(意味着要维护过去的数据)。

全局终止的条件是到达某个坐标后发现切换各个方向都不能走下一步,则全局结束。

1暴力迭代法

地图走法,硬代码实现问题分析的规则

2层序剥开、收缩边界

不断收缩边界,层序遍历


3.代码实例

暴力迭代法 

  1 class Solution {
  2   public:
  3     const int dirCount = 4; //可选方向数量
  4     const int dirRight = 0, dirDown = 1, dirLeft = 2, dirUp = 3;
  5     vector<int> printMatrix(vector<vector<int> > matrix) {
  6         //输入矩阵尺寸校验
  7         vector<int> ret;
  8         if (matrix.size() <= 0 || matrix[0].size() <= 0) {
  9             return ret;
 10         }
 11         int rowSize = matrix.size();
 12         int colSize = matrix[0].size();
 13 
 14         //初始化中间参数
 15         vector<vector<bool>> passedFlag(rowSize, vector<bool>(colSize, false));
 16         int curDir = dirRight;
 17         int curRow = 0, curCol = 0;
 18         int nextRow = 0, nextCol = 0;
 19         bool canNext = false;
 20         int dirWatchDog = 0;//当所有方向都不能继续时触发终止
 21 
 22         //迭代
 23         while (true) {
 24             //在当前方向上遍历元素
 25             while (true) {
 26                 //标记当前坐标
 27                 ret.push_back(matrix[curRow][curCol]);
 28                 passedFlag[curRow][curCol] = true;
 29 
 30                 //使用当前方向和坐标获取下一步坐标
 31                 nextRow = curRow;
 32                 nextCol = curCol;
 33                 canNext = getNextStep(curDir, rowSize, colSize, nextRow, nextCol);
 34                 //该方向无下一个坐标
 35                 if (!canNext) {
 36                     break;
 37                 }
 38                 //该方向上下一个坐标已占用
 39                 if (passedFlag[nextRow][nextCol]) {
 40                     break;
 41                 }
 42 
 43                 //可以切下一步
 44                 curRow = nextRow;
 45                 curCol = nextCol;
 46             }
 47 
 48             //换到下一个方向
 49             dirWatchDog = 0; //初始化看门狗
 50             while (true) {
 51                 //先切到下一个方向
 52                 curDir++;
 53                 dirWatchDog++;//切方向计数
 54 
 55                 //检查看门狗溢出
 56                 if (dirWatchDog > dirCount) {
 57                     return ret;
 58                 }
 59 
 60                 //检查该方向是否可行
 61                 if (curDir > dirUp) {
 62                     curDir = dirRight;
 63                 }
 64                 
 65                 //使用当前方向和坐标获取下一步坐标                
 66                 nextRow = curRow;
 67                 nextCol = curCol;
 68                 canNext = getNextStep(curDir, rowSize, colSize, nextRow, nextCol);
 69                 //该方向无下一个坐标
 70                 if (!canNext) {
 71                     continue;
 72                 }
 73                 //该方向上下一个坐标已占用
 74                 if (passedFlag[nextRow][nextCol]) {
 75                     continue;
 76                 }
 77 
 78                 //找到了可以继续的方向
 79                 curRow = nextRow;
 80                 curCol = nextCol;
 81                 break;
 82             }
 83         }
 84         return ret;
 85     }
 86 
 87     //获取指定方向上的下一步坐标
 88     bool getNextStep(const int dir, const int rowSize, const int colSize,
 89                      int& rowId,
 90                      int& colId) {
 91         switch (dir) {
 92             case 0:
 93                 if ((colId + 1) >= colSize) {
 94                     return false;
 95                 }
 96                 colId++;
 97                 break;
 98             case 1:
 99                 if ((rowId + 1) >= rowSize) {
100                     return false;
101                 }
102                 rowId++;
103                 break;
104             case 2:
105                 if ((colId - 1) < 0) {
106                     return false;
107                 }
108                 colId--;
109                 break;
110             case 3:
111                 if ((rowId - 1) < 0) {
112                     return false;
113                 }
114                 rowId--;
115                 break;
116             default:
117                 return false;
118         }
119         return true;
120     }
121 };
View Code

 收缩边界

 1 class Solution {
 2 public:
 3     vector<int> printMatrix(vector<vector<int> > matrix) {
 4         vector<int> res;
 5         int n = matrix.size();
 6         //先排除特殊情况
 7         if(n == 0) 
 8             return res;
 9         //左边界
10         int left = 0; 
11         //右边界
12         int right = matrix[0].size() - 1; 
13         //上边界
14         int up = 0; 
15         //下边界
16         int down = n - 1; 
17         //直到边界重合
18         while(left <= right && up <= down){ 
19             //上边界的从左到右
20             for(int i = left; i <= right; i++) 
21                 res.push_back(matrix[up][i]); 
22             //上边界向下
23             up++; 
24             if(up > down)
25                 break;
26             //右边界的从上到下
27             for(int i = up; i <= down; i++) 
28                 res.push_back(matrix[i][right]);
29             //右边界向左
30             right--; 
31             if(left > right)
32                 break;
33             //下边界的从右到左
34             for(int i = right; i >= left; i--) 
35                 res.push_back(matrix[down][i]);
36             //下边界向上
37             down--; 
38             if(up > down)
39                 break; 
40             //左边界的从下到上
41             for(int i = down; i >= up; i--) 
42                 res.push_back(matrix[i][left]);
43             //左边界向右
44             left++; 
45             if(left > right)
46                 break;
47         }
48         return res;
49     }
50 };
View Code

 

posted @ 2022-12-03 13:04  啊原来是这样呀  阅读(34)  评论(0)    收藏  举报