剑指offer29:顺时针打印矩阵

采用按层模拟顺时针分析如下:

1.考虑何时停止顺时针遍历:

由于是按层数start进行遍历,顺时针的起点为(start,start),可以尝试画一下3X3,4X4的矩阵,可以发现循环可以继续的条件是,列数>2*start,对行同样成立。

2.接着考虑顺时针遍历写法,主要考虑边界条件,这里cv剑指offer的分析:

首先说明顺时针打印的规则,第一次打印最上面一行,从左至右(start,[start,endCol])全部打印,第二次打印从上至下([start+1,endRow],endCol),第三次打印最下面一行,从右至左(endRow,[endCol-1,start]),第四次从下至上,([endRow-1,start+1],start)

至于每次要打印的行列的终点:

endRow=总行数-1-start

endCol=总列数-1-start

接下来对应图中的三种特殊情况做边界分析

1.从左至右一行:此时只要打印第一行即可,由于我们的打印方式,所以无论如何第一行是肯定可以打印的,不需要判断条件。

2.从上至下一列:第二张图其实是告诉我们什么情况下才能打印从上至下的这一列,对比第一种特殊情况,为什么第一种情况不能打印从上至下的一列呢,从区间可以看出,这一列的坐标是([start+1,endRow],endCol),因此我们要保证start<endRow才行,若取等于,则是第一种特殊情况,小于保证了至少有从上至下的一种情况,看第三个图也可知晓。

3.从右至左一行:对比图2图3,我们知道要想能打印这一行,根据第三个区间(endRow,[endCol-1,start])来看,是由于区间长度(endCol-1-start)+1>=1才有机会打印即start<endCol,并且还有一个前提是要能够打印从上至下的一列即start<endRow,否则可能退化成图1的情况。

4.从下至上一列,同样可由区间长度endRow-1-(start+1)+1>=1可得出打印条件start<endRow-1,另外的一个前提是,可以打印从右至左的一行,否则可能退化成图2的情况,即同时满足start<endRow&&start<endCol和start<endRow-1,最后变成start<endRow-1&&start<endCol。

代码如下所示:

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if(matrix.size()==0||matrix[0].size()==0) return {};
        int start=0;
        vector<int> ans;
        int rows=matrix.size();
        int cols=matrix[0].size();
        while(rows>start*2&&cols>start*2)
        {
            int endRow=rows-1-start;
            int endCol=cols-1-start;
            //从左至右
            for(int i=start;i<=endCol;++i)
            {
                ans.push_back(matrix[start][i]);
            }
            //最后只有一行的情况 不用打印从上至下的一列
            //可以用[start,endRow]的大小关系来判断是否需要打印
            if(start<endRow)
            {
                for(int i=start+1;i<=endRow;++i)
                {
                    ans.push_back(matrix[i][endCol]);
                }
            }

            //能打印从右至左的一行的条件是
            //1.能打印出从上至下的一列
            //2.[start,endCol]的大小约束关系
            if(start<endCol&&start<endRow)
            {
                for(int i=endCol-1;i>=start;--i)
                {
                    ans.push_back(matrix[endRow][i]);
                }
            }

            //能打印从下至上的条件是
            //1.start<endCol以保证可以从左至右
            //2.start<endRow-1以保证从上至下和从右至左,并且可以从下至上
            if(start<endCol&&start<endRow-1)
            {
                for(int i=endRow-1;i>start;--i)
                {
                    ans.push_back(matrix[i][start]);
                }
            }

            ++start;
        }
        return ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值