• LeetCode: Spiral Matrix 解题报告


    Spiral Matrix
    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].

    Solution 1:

    使用递归,一次扫描一整圈,然后用x,y记录这个圈的左上角,递归完了都+1。rows, cols记录还没扫的有多少。思想比较简单,但相当容易出错。起码提交了5次才最后过。

    注意:1. 扫描第一行跟最后一行要扫到底部为止,而扫描左列和右列只需要扫中间的。

    1  2  3   4

    5  6  7   8

    9 10 11 12

    例如以上例子: 你要 先扫1234, 然后是8,然后是12 11 10 9 然后是 5.

    不能这样:123, 4 8, 12 11 10 , 9 5。 用后者的方法在只有一个数字 1的时候 就完全不会扫到它。

     1 public List<Integer> spiralOrder1(int[][] matrix) {
     2         List<Integer> ret = new ArrayList<Integer>();
     3         if (matrix == null || matrix.length == 0 
     4             || matrix[0].length == 0) {
     5             return ret;   
     6         }
     7         
     8         rec(matrix, 0, 0, matrix.length, matrix[0].length, ret);
     9         
    10         return ret;
    11     }
    12     
    13     public static void rec(int[][] matrix, int x, int y, int rows, int cols, List<Integer> ret) {
    14         if (rows <= 0 || cols <= 0) {
    15             return;
    16         }
    17         
    18         // first line
    19         for (int i = 0; i < cols; i++) {
    20             ret.add(matrix[x][y + i]);
    21         }
    22         
    23         // right column
    24         for (int i = 1; i < rows - 1; i++) {
    25             ret.add(matrix[x + i][y + cols - 1]);
    26         }
    27         
    28         // down row
    29         if (rows > 1) {
    30             for (int i = cols - 1; i >= 0; i--) {
    31                 ret.add(matrix[x + rows - 1][y + i]);
    32             }    
    33         }
    34         
    35         // left column. GO UP.
    36         if (cols > 1) {
    37             for (int i = rows - 2; i > 0; i--) {
    38                 ret.add(matrix[x + i][y]);
    39             }    
    40         }
    41         
    42         rec (matrix, x + 1, y + 1, rows - 2, cols - 2, ret);
    43     }
    View Code

    Solution 2:

    http://blog.csdn.net/fightforyourdream/article/details/16876107?reload

    感谢以上文章作者提供的思路,我们可以用x1,y1记录左上角,x2,y2记录右下角,这样子我们算各种边界值会方便好多。也不容易出错。

     1 /*
     2     Solution 2:
     3         REF: http://blog.csdn.net/fightforyourdream/article/details/16876107?reload
     4         此算法比较不容易算错
     5     */
     6     public List<Integer> spiralOrder2(int[][] matrix) {
     7         List<Integer> ret = new ArrayList<Integer>();
     8         if (matrix == null || matrix.length == 0 
     9             || matrix[0].length == 0) {
    10             return ret;   
    11         }
    12         
    13         int x1 = 0;
    14         int y1 = 0;
    15         
    16         int rows = matrix.length;
    17         int cols = matrix[0].length;
    18         
    19         while (rows >= 1 && cols >= 1) {
    20             // Record the right down corner of the matrix.
    21             int x2 = x1 + rows - 1;
    22             int y2 = y1 + cols - 1;
    23             
    24             // go through the WHOLE first line.
    25             for (int i = y1; i <= y2; i++) {
    26                 ret.add(matrix[x1][i]);
    27             }
    28             
    29             // go through the right column.
    30             for (int i = x1 + 1; i < x2; i++) {
    31                 ret.add(matrix[i][y2]);
    32             }
    33             
    34             // go through the WHOLE last row.
    35             if (rows > 1) {
    36                 for (int i = y2; i >= y1; i--) {
    37                     ret.add(matrix[x2][i]);
    38                 }    
    39             }
    40             
    41             // the left column.
    42             if (cols > 1) {
    43                 for (int i = x2 - 1; i > x1; i--) {
    44                     ret.add(matrix[i][y1]);
    45                 }
    46             }    
    47             
    48             // in one loop we deal with 2 rows and 2 cols.
    49             rows -= 2;
    50             cols -= 2;
    51             x1++;
    52             y1++;
    53         }
    54         
    55         return ret;
    56     }
    View Code

    Solution 3:

    http://fisherlei.blogspot.com/2013/01/leetcode-spiral-matrix.html

    感谢水中的鱼大神。这是一种相当巧妙的思路,我们这次可以用Iterator来实现了,记录2个方向数组,分别表示在x方向,y方向的前进方向。1表示右或是下,-1表示左或是向上,0表示不动作。

    // 1: means we are visiting the row by the right direction.
    // -1: means we are visiting the row by the left direction.
    int[] x = {1, 0, -1, 0};
            
    // 1: means we are visiting the colum by the down direction.
    // -1: means we are visiting the colum by the up direction.
    int[] y = {0, 1, 0, -1};

    这种方向矩阵将会很常用在各种旋转数组上。

     1 /*
     2     Solution 3:
     3     使用方向矩阵来求解
     4     */
     5     
     6     public List<Integer> spiralOrder(int[][] matrix) {
     7         List<Integer> ret = new ArrayList<Integer>();
     8         if (matrix == null || matrix.length == 0 
     9             || matrix[0].length == 0) {
    10             return ret;   
    11         }
    12         
    13         int rows = matrix.length;
    14         int cols = matrix[0].length;
    15         
    16         int visitedRows = 0;
    17         int visitedCols = 0;
    18 
    19         // indicate the direction of x    
    20         
    21         // 1: means we are visiting the row by the right direction.
    22         // -1: means we are visiting the row by the left direction.
    23         int[] x = {1, 0, -1, 0};
    24         
    25         // 1: means we are visiting the colum by the down direction.
    26         // -1: means we are visiting the colum by the up direction.
    27         int[] y = {0, 1, 0, -1};
    28         
    29         // 0: right, 1: down, 2: left, 3: up.
    30         int direct = 0;
    31         
    32         int startx = 0;
    33         int starty = 0;
    34         
    35         int candidateNum = 0;
    36         int step = 0;
    37         while (true) {
    38             if (x[direct] == 0) {
    39                 // visit Y axis.
    40                 candidateNum = rows - visitedRows;
    41             } else {
    42                 // visit X axis
    43                 candidateNum = cols - visitedCols;
    44             }
    45             
    46             if (candidateNum <= 0) {
    47                 break;
    48             }
    49             
    50             ret.add(matrix[startx][starty]);
    51             step++;
    52             
    53             if (step == candidateNum) {
    54                 step = 0;
    55                 visitedRows += x[direct] == 0 ? 0: 1;
    56                 visitedCols += y[direct] == 0 ? 0: 1;
    57                 
    58                 // move forward the direction.
    59                 direct ++;
    60                 direct = direct%4;
    61             }
    62             
    63             // 根据方向来移动横坐标和纵坐标。
    64             startx += y[direct];
    65             starty += x[direct];
    66         }
    67         
    68         return ret;
    69     }
    View Code

    SOLUTION 4 (December 2nd 更新):

    对solution 2改进了一下,使用top,bottom,right,left记录四个角。程序更简洁漂亮。

     1 public class Solution {
     2     public List<Integer> spiralOrder(int[][] matrix) {
     3         List<Integer> ret = new ArrayList<Integer>();
     4         if (matrix == null ||matrix.length == 0) {
     5             // 注意在非法的时候,应该返回空解,而不是一个NULL值
     6             return ret;
     7         }
     8         
     9         // Record how many rows and cols we still have.
    10         int rows = matrix.length;
    11         int cols = matrix[0].length;
    12         
    13         // The four coners.
    14         int top = 0;
    15         int left = 0;
    16         int bottom = rows - 1;
    17         int right = cols - 1;
    18         
    19         // every time we go through two rows and two cols.
    20         for (; rows > 0 && cols > 0; rows -= 2, cols -= 2, top++, left++, bottom--, right--) {
    21             // the first line.
    22             for (int i = left; i <= right; i++) {
    23                 ret.add(matrix[top][i]);
    24             } 
    25             
    26             // the right column.
    27             for (int i = top + 1; i < bottom; i++) {
    28                 ret.add(matrix[i][right]);
    29             }
    30             
    31             // the down line;
    32             if (rows > 1) {
    33                 for (int j = right; j >= left; j--) {
    34                     ret.add(matrix[bottom][j]);
    35                 }
    36             }
    37             
    38             // the left column.
    39             if (cols > 1) {
    40                 for (int i = bottom - 1; i > top; i --) {
    41                     ret.add(matrix[i][left]);
    42                 }
    43             }
    44         }
    45         
    46         return ret;
    47     }
    48 }
    View Code

    2015.1.9 redo:

    可以不用rows/cols来记录行列数。只需要判断四个边界是否相撞即可。

     1 public List<Integer> spiralOrder3(int[][] matrix) {
     2         List<Integer> ret = new ArrayList<Integer>();
     3         if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
     4             return ret;
     5         }
     6         
     7         int rows = matrix.length;
     8         int cols = matrix[0].length;
     9         
    10         int left = 0;
    11         int right = cols - 1;
    12         int top = 0;
    13         int bottom = rows - 1;
    14         
    15         while (left <= right && top <= bottom) {
    16             // line top.
    17             for (int i = left; i <= right; i++) {
    18                 ret.add(matrix[top][i]);
    19             }
    20             
    21             // line right;
    22             for (int i = top + 1; i <= bottom - 1; i++) {
    23                 ret.add(matrix[i][right]);
    24             }
    25             
    26             // line bottom.
    27             if (top != bottom) {
    28                 for (int i = right; i >= left; i--) {
    29                     ret.add(matrix[bottom][i]);
    30                 }    
    31             }
    32             
    33             // line left;
    34             if (left != right) {
    35                 for (int i = bottom - 1; i >= top + 1; i--) {
    36                     ret.add(matrix[i][left]);
    37                 }    
    38             }
    39             
    40             left++;
    41             right--;
    42             top++;
    43             bottom--;
    44         }
    45         
    46         return ret;
    47     }
    View Code

    GitHub CODE:

    spiralOrder.java

  • 相关阅读:
    centos 安装python3.6 简易安装过程
    包装类型
    剑指offer二叉树中和为某一值的路径
    剑指offer 捡绳子
    按位与的技巧
    SpringBoot 登录拦截功能的实现
    AIO实现简单http服务器
    真题-数的分解
    重建二叉树
    旋转数组的最小数字
  • 原文地址:https://www.cnblogs.com/yuzhangcmu/p/4046543.html
Copyright © 2020-2023  润新知