又是一道关于旋转矩阵的问题,思路都很固定,但具体写的时候很容易出错
package Level4;
import java.util.ArrayList;
/**
* 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].
Discuss
*
*/
public class S54 {
public static void main(String[] args) {
// int[][] matrix = {{1,2,3,4,5},
// {14,15,16,17,6},
// {13,20,19,18,7},
// {12,11,10,9,8}};
int[][] matrix = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
// int[][] matrix = {{1,2,3}};
System.out.println(spiralOrder(matrix));
}
public static ArrayList<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> ret = new ArrayList<Integer>();
if(matrix.length == 0){
return ret;
}
int m = matrix.length;
int n = matrix[0].length;
int margin = 1;
// rec(matrix, m, n, margin, 0, 0, ret);
rec2(matrix, m, n, 0, ret);
return ret;
}
/*
n
______________(x,y+n-1)
|(x,y) |
| | m
|_____________ |
(x+m-1,y) (x+m-1,y+n-1)
m: 矩阵高度
n: 矩阵宽度
margin: 每次变化后减少量,此题固定为1
x,y: 左上角坐标
可以推出,右上角坐标为(y+n)
*/
public static void rec(int[][] matrix, int m, int n, int margin, int x, int y, ArrayList<Integer> ret){
if(m<=0 || n<=0){
return;
}
if(m==1 && n==1){ // 只包含一个元素的情况
ret.add(matrix[x][y]);
return;
}else if(m==1 && n!=1){ // 只有一行的情况
for(int j=y; j<y+n; j++){
ret.add(matrix[y][j]);
}
return;
}else if(m!=1 && n==1){ // 只有一列的情况
for(int i=x; i<x+m; i++){
ret.add(matrix[i][x]);
}
return;
}
// 以下是有多行多列的情况
for(int i=y; i<y+n-margin; i++){ // 向右
ret.add(matrix[x][i]);
}
for(int i=x; i<x+m-margin; i++){ // 向下
ret.add(matrix[i][y+n-margin]);
}
for(int i=y+n-margin; i>x; i--){ // 向左
ret.add(matrix[x+m-margin][i]);
}
for(int i=x+m-margin; i>x; i--){ // 向上
ret.add(matrix[i][y]);
}
rec(matrix, m-2, n-2, margin, x+1, y+1, ret); // 改变长宽度和初始点位置
}
// http://leetcode.com/2010/05/printing-matrix-in-spiral-order.html
// m: 行数 n:列数 k:第几层
public static void rec2(int[][] matrix, int m, int n, int k, ArrayList<Integer> ret){
if(m<=0 || n<=0){
return;
}
if(m == 1){ // 只有一行时
for(int j=0; j<n; j++){
ret.add(matrix[k][k+j]);
}
return;
}
if(n == 1){ // 只有一列时
for(int i=0; i<m; i++){
ret.add(matrix[k+i][k]);
}
return;
}
for(int j=0; j<n-1; j++){ // 从左上第一个到右上倒二个
ret.add(matrix[k][k+j]);
}
for(int i=0; i<m-1; i++){ // 从右上第一个到右下倒二个
ret.add(matrix[k+i][k+n-1]);
}
for(int j=0; j<n-1; j++){ // 从右下第一个到左下倒二个
ret.add(matrix[k+m-1][k+n-1-j]);
}
for(int i=0; i<m-1; i++){ // 从左下第一个到左上倒二个
ret.add(matrix[k+m-1-i][k]);
}
rec2(matrix, m-2, n-2, k+1, ret); // 剩下m-2行和n-2列,k+1 level
}
}
终于找到一种不容易写错的方法,要点就是在定义递归时用(x1,y1), (x2,y2)来限制当前考虑矩阵的左上角和右下角。这样就能方便非常多。但要保证左上角的位置必须小于右下角的位置!
public class Solution {
public static List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ret = new ArrayList<Integer>();
if(matrix.length == 0) {
return ret;
}
rec(matrix, ret, 0, 0, matrix.length-1, matrix[0].length-1);
return ret;
}
public static void rec(int[][] matrix, List<Integer> ret, int x1, int y1, int x2, int y2) {
int m = x2 - x1 + 1;
if(x1 > x2 || y1 > y2) { // (x1,y1) must be smaller than (x2,y2)
return;
}
if(m <= 0) { // empty
return;
}
if(m == 1) { // single row
for(int j=y1; j<=y2; j++) {
ret.add(matrix[x1][j]);
}
return;
}
int n = y2 - y1 + 1;
if(n == 1) { // single column
for(int i=x1; i<=x2; i++) {
ret.add(matrix[i][y1]);
}
return;
}
for(int j=y1; j<y2; j++) {
ret.add(matrix[x1][j]);
}
for(int i=x1; i<x2; i++) {
ret.add(matrix[i][y2]);
}
for(int j=y2; j>y1; j--) {
ret.add(matrix[x2][j]);
}
for(int i=x2; i>x1; i--) {
ret.add(matrix[i][y1]);
}
rec(matrix, ret, x1+1, y1+1, x2-1, y2-1); // shrink boundary
}
}