LeetCode54 螺旋矩阵

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

Example 1:

Input:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
Output: [1,2,3,6,9,8,7,4,5]

Example 2:

Input:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
Output: [1,2,3,4,8,12,11,10,9,5,6,7]

2. solution

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) 
    {
           List ans = new ArrayList();
        if (matrix.length == 0) return ans;

        int m = matrix.length;
        int n = matrix[0].length;

        // 定义一个记录访问情况数组matrix2, 0代表未访问,1代表已访问
        int [][]matrix2 = new int[m][n];
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                matrix2[i][j] = 0;
            }
        }


        // 总共要输出sum = m*n
        int num = 1,sum =m*n;
        int i=0,j=0;

        //action 4个值代表4个动作
        //0:right 1:dowm 2:left 3:up
        int action = 0;

        // 碰壁时移动行为只有4种情况
        int[] i_action = {1, -1, -1, 1};
        int[] j_action = {-1, -1, 1, 1};
        while(num <= sum)
        {
            // 如果该位置正确,且没有被访问到
            if( 0<=i && i<m && 0<=j && j<n && matrix2[i][j]==0)
            {
                // 输出,并把matrix2标记为已访问
                System.out.print(matrix[i][j]);
                matrix2[i][j]=1;
                // 计数加1
                num++;
                ans.add(matrix[i][j]);

                // 根据相应action改变位置
                switch (action)
                {
                    case 0:
                        j++;
                        break;
                    case 1:
                        i++;
                        break;
                    case 2:
                        j--;
                        break;
                    default:
                        i--;
                        break;
                }

            }

            // 碰壁时的面对的4个情形是循环出现的,可以用一个长度为4的数组存储解决方案,根据action的值来决定采用哪个方案
            else
            {
                i += i_action[action];
                j += j_action[action];
                // 碰壁:更新移动方向
                action = (action+1)%4;
            }
        }

        return ans;
    }
}

When traversing the matrix in the spiral order, at any time we follow one out of the following four directions: RIGHT DOWN LEFT UP. Suppose we are working on a 5 x 3 matrix as such:

0 1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

Imagine a cursor starts off at (0, -1), i.e. the position at ‘0’, then we can achieve the spiral order by doing the following:

  1. Go right 5 times
  2. Go down 2 times
  3. Go left 4 times
  4. Go up 1 times.
  5. Go right 3 times
  6. Go down 0 times -> quit

Notice that the directions we choose always follow the order ‘right->down->left->up’, and for horizontal movements, the number of shifts follows:{5, 4, 3}, and vertical movements follows {2, 1, 0}.

Thus, we can make use of a direction matrix that records the offset for all directions, then an array of two elements that stores the number of shifts for horizontal and vertical movements, respectively. This way, we really just need one for loop instead of four.

Another good thing about this implementation is that: If later we decided to do spiral traversal on a different direction (e.g. Counterclockwise), then we only need to change the Direction matrix; the main loop does not need to be touched.

vector<int> spiralOrder(vector<vector<int>>& matrix) {
    vector<vector<int> > dirs{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    vector<int> res;
    int nr = matrix.size();     if (nr == 0) return res;
    int nc = matrix[0].size();  if (nc == 0) return res;
    
    vector<int> nSteps{nc, nr-1};
    
    int iDir = 0;   // index of direction.
    int ir = 0, ic = -1;    // initial position
    while (nSteps[iDir%2]) {
        for (int i = 0; i < nSteps[iDir%2]; ++i) {
            ir += dirs[iDir][0]; ic += dirs[iDir][1];
            res.push_back(matrix[ir][ic]);
        }
        nSteps[iDir%2]--;
        iDir = (iDir + 1) % 4;
    }
    return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值