LeetCode: Spiral Matrix 解题报告

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

相关推荐