LeetCode(54) SpiralMatrix

题目如下:

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
For example,
Given the following matrix:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
You should return [1,2,3,6,9,8,7,4,5].

分析如下:

题目的意思是,按照顺时针方向旋转着遍历矩阵,把遍历结果返回。关键是怎么理解旋转的含义?

可以这样来思考。以上面的矩阵为例。

step one: 1,2

step two: 3,6

step three: 9,8

step four: 7,4

这样完成了对最外层的遍历,剥去一层之后(leetcode官网上说,想象剥洋葱那样剥去一层),继续往下剥,去掉次外层,不断进行下去,直到边界条件。显然边界条件是最后只剩1个点,或者一行,或者一列,导致没法拐个弯形成一个矩形。

那么边界条件是什么时候可能发生呢?这是本题最坑爹的地方了,我在这里写了很久才找到正确的边界条件判断语句。

需要写几个4*4, 4*6, 4*2, 5*5, 5*3, 5*7, 4*5, 4*3, 5*4, 5*6例子自己看看,这样才能看出来。


结合看上面的图,可以知道,

1 在rowcount 和colcount中选较小值。到底剥洋葱剥了几层由较小值决定。

2 如果较小值是奇数,那么剥洋葱到最后会产生一条单独的线段。如果较小值是偶数,然么剥洋葱到最后就会完成所有点的打印,不会留有单独的线段。


上面的做法是顺着题意思考的做法,思考边界条件的地方非常坑爹。

还有一种做法是递归,参见leetcode官网的解释,代码量顿时减少很多,虽然时间慢一些,但是本题的递归并没产生太多重复的计算,所以时间空间的开销都是可以忍的。

我的代码:

// 4ms过大集合
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int> > &matrix) {
        vector<int> res;
        int row=(int)matrix.size();
        if(row==0)
            return res;
        int col=(int)matrix[0].size();
        if(col==0)
            return res;
        int count=row<col?row:col;
        for(int i=0;i<count/2;i++){
            for(int j=i;j<col-1-i;j++)
                res.push_back(matrix[i][j]);
            for(int j=i;j<row-1-i;j++)
                res.push_back(matrix[j][col-i-1]);
            for(int j=col-1-i;j>i;j--)
                res.push_back(matrix[row-1-i][j]);
            for(int j=row-1-i;j>i;j--)
                res.push_back(matrix[j][i]);
        }
        //单独处理在最后可能出现的单列或者单行的情况
        if(row%2==1&&col%2==1){ //行数为奇,列数为奇,必然需要处理单行或单列
            if(row<=col){
                for(int i=0;i<=col-row;i++)
                    res.push_back(matrix[row/2][row/2+i]);
            }else{
                for(int i=0;i<=row-col;i++)
                    res.push_back(matrix[col/2+i][col/2]);
            }
        }else if(row%2==1&&col%2==0){ //行数为奇,列数为偶,仅当row<col才需要处理单行或单列
            if(row<col){
                for(int i=0;i<=col-row;i++)
                    res.push_back(matrix[row/2][row/2+i]);
            }
        }else if(row%2==0&&col%2==1){//行数为偶,列数为奇,仅当col<row才需要处理单行或单列
            if(col<row){
                for(int i=0;i<=row-col;i++)
                    res.push_back(matrix[col/2+i][col/2]);
            }
        }
        return res;
   }
};

//leetcode官网解答
void print_spiral(int mat[][N_MAX], int m, int n, int k) {
  if (m <= 0 || n <= 0)
    return;
  if (m == 1) {
    for (int j = 0; j < n; j++)
      cout << mat[k][k+j] << " ";
    return;
  }
  if (n == 1) {
    for (int i = 0; i < m; i++)
      cout << mat[k+i][k] << " ";
    return;
  }
  // print from top left
  for (int j = 0; j < n - 1; j++)
    cout << mat[k][k+j] << " ";
  // print from top right
  for (int i = 0; i < m - 1; i++)
    cout << mat[k+i][k+n-1] << " ";
  // print from bottom right
  for (int j = 0; j < n - 1; j++)
    cout << mat[k+m-1][k+n-1-j] << " ";
  // print from bottom left
  for (int i = 0; i < m - 1; i++)
    cout << mat[k+m-1-i][k] << " ";
 
  print_spiral(mat, m-2, n-2, k+1);
}
 
void print_spiral_helper(int mat[][N_MAX], int m, int n) {
  print_spiral(mat, m, n, 0);
}

题目小结:

(1) 这道题写了很久才写出来。首先是没有想到用递归,如果用递归,可以很快写出来。其次是,就算没有想到用递归,那么迭代版依然花了很长时间,这里面的时间大量花费在没有真正想清楚边界条件就去着急写code了。所以如果没有想清楚,不要着急写。最省时间的方式是先想清楚了再写。


update: 2015-01-10

//4ms 
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int> > &matrix) {
        vector<int> res;
        int nRow = matrix.size();
        if (nRow == 0) return res;
        int nCol = matrix[0].size();
        if (nCol == 0) return res;
        if (nRow == 1) return matrix[0];
        if (nCol == 1) {
            for (int i = 0; i < nRow; ++i)
                res.push_back(matrix[i][0]);
            return res;
        }
        
        int offset_range = nRow < nCol ? nRow/2 : nCol/2;

        for (int offset = 0; offset < offset_range; ++offset) {
            
            // up
            for (int i = offset; i < nCol - offset - 1; ++i) {
                res.push_back(matrix[offset][i]);
            }
        
            // right
            for (int i = offset; i < nRow - offset - 1; ++i) {
                res.push_back(matrix[i][nCol - offset - 1]);
            }
        
            //down
            for (int i = nCol - offset - 1; i >= 1 + offset; --i) {
                res.push_back(matrix[nRow - offset - 1][i]);
            }        
        
            //left
            for (int i = nRow - offset - 1; i >= 1 + offset; --i) {
                res.push_back(matrix[i][offset]);
            }        
        }
        
        if (nRow < nCol && nRow % 2 == 1) {
            for (int i = offset_range; i < nCol - offset_range; ++i ) {
                res.push_back(matrix[nRow/2][i]);
            }
        } else if (nRow >= nCol && nCol %2 == 1) {
            for (int i = offset_range; i < nRow - offset_range; ++i) {
                res.push_back(matrix[i][nCol/2]);
            }
        }
        
        return res;
    }
};

这道题目还有 续集 Spiral Matrix II,其实本质是同一道题目。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值