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].
Java Solution 1
If more than one row and column left, it can form a circle and we process the circle. Otherwise, if only one row or column left, we process that column or row ONLY.
public class Solution { public ArrayList<Integer> spiralOrder(int[][] matrix) { ArrayList<Integer> result = new ArrayList<Integer>(); if(matrix == null || matrix.length == 0) return result; int m = matrix.length; int n = matrix[0].length; int x=0; int y=0; while(m>0 && n>0){ //if one row/column left, no circle can be formed if(m==1){ for(int i=0; i<n; i++){ result.add(matrix[x][y++]); } break; }else if(n==1){ for(int i=0; i<m; i++){ result.add(matrix[x++][y]); } break; } //below, process a circle //top - move right for(int i=0;i<n-1;i++){ result.add(matrix[x][y++]); } //right - move down for(int i=0;i<m-1;i++){ result.add(matrix[x++][y]); } //bottom - move left for(int i=0;i<n-1;i++){ result.add(matrix[x][y--]); } //left - move up for(int i=0;i<m-1;i++){ result.add(matrix[x--][y]); } x++; y++; m=m-2; n=n-2; } return result; } } |
Similarly, we can write the solution this way:
public List<Integer> spiralOrder(int[][] matrix) { List<Integer> result = new ArrayList<Integer>(); if(matrix==null||matrix.length==0||matrix[0].length==0) return result; int m = matrix.length; int n = matrix[0].length; int left=0; int right=n-1; int top = 0; int bottom = m-1; while(result.size()<m*n){ for(int j=left; j<=right; j++){ result.add(matrix[top][j]); } top++; for(int i=top; i<=bottom; i++){ result.add(matrix[i][right]); } right--; //prevent duplicate row if(bottom<top) break; for(int j=right; j>=left; j--){ result.add(matrix[bottom][j]); } bottom--; // prevent duplicate column if(right<left) break; for(int i=bottom; i>=top; i--){ result.add(matrix[i][left]); } left++; } return result; } |
Java Solution 2
We can also recursively solve this problem. The solution’s performance is not better than Solution 1. Therefore, Solution 1 should be preferred.
public class Solution { public ArrayList<Integer> spiralOrder(int[][] matrix) { if(matrix==null || matrix.length==0) return new ArrayList<Integer>(); return spiralOrder(matrix,0,0,matrix.length,matrix[0].length); } public ArrayList<Integer> spiralOrder(int [][] matrix, int x, int y, int m, int n){ ArrayList<Integer> result = new ArrayList<Integer>(); if(m<=0||n<=0) return result; //only one element left if(m==1&&n==1) { result.add(matrix[x][y]); return result; } //top - move right for(int i=0;i<n-1;i++){ result.add(matrix[x][y++]); } //right - move down for(int i=0;i<m-1;i++){ result.add(matrix[x++][y]); } //bottom - move left if(m>1){ for(int i=0;i<n-1;i++){ result.add(matrix[x][y--]); } } //left - move up if(n>1){ for(int i=0;i<m-1;i++){ result.add(matrix[x--][y]); } } if(m==1||n==1) result.addAll(spiralOrder(matrix, x, y, 1, 1)); else result.addAll(spiralOrder(matrix, x+1, y+1, m-2, n-2)); return result; } } |
I found that solution is very popular and helpful : https://www.youtube.com/watch?v=ZUvKzWYb3Cg
Here mine hope it will help…
Unfortunately I had to add break lines… It’s less elegant.
public static void main(String[] args) {
int matrix [] [] =
{
{1,2,3},
{4,5,6,},
{7,8,9}
};
int nbLine = matrix.length;
int nbCol = matrix[0].length;
int nbLineB = 0;
int nbColB = 0;
int element = nbLine * nbCol;
int index = 0;
ArrayList response = new ArrayList();
// While loop
while( element > index)
{
// Move to the right
if(element == index) break;
for(int i =nbColB; i < nbCol; i++, index++)
{
response.add(matrix[nbColB][i]);
}
// Move Down
if(element == index) break;
for(int i = nbLineB+1; i = nbColB; i–, index++)
{
response.add(matrix[nbLine-1][i]);
}
nbLine–;
nbLineB++;
// Move Up
if(element == index) break;
for ( int i = nbLine-1; i >= nbLineB ; i–, index++)
{
response.add(matrix[i][nbColB]);
}
nbColB++;
}
// Print
for(Integer value : response)
{
System.out.print(value + ” “);
}
// Or return… ( don’t forget to change method signature )
//return response;
Well, technically it is a correct answer as it enumerates the matrix elements in a spiral order.
It just starts the traversal down instead of to the right 🙂
If you flip the assigned values on line 9:
int sideLen = mx[0].length, nextSideLen = mx.length;
and flip the indexes on line 18:
result.add(mx[y][x]);
I suppose this should fix the spiraling direction.
For an input of { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, {9,10,11,12} } -> the output is [1, 5, 9, 10, 11, 12, 8, 4, 3, 2, 6, 7] instead of [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7], so basically the code is producing wrong output.
Simplified solution with two major design improvements:
1) no code duplication;
2) traversal is done with one loop i.e. you can easily convert the function into iterator over the matrix cells;
public static List getSpiralTraversal(int[][] mx) {
List result = new ArrayList();
// Set initial direction
int dx = 1, dy = 0;
// Set the starting point before the first mx cell
int x = -1, y = 0;
// Set the first side length and the next side length
int sideLen = mx.length, nextSideLen = mx[0].length;
int sideCounter = sideLen;
// While both of the run lengths are non-zero
while (sideLen > 0 && nextSideLen > 0) {
if (sideCounter > 0) {
// traverse the side while counter is > 0
sideCounter--;
x += dx;
y += dy;
result.add(mx[x][y]);
} else {
// switch direction when the counter is 0
int tmp;
// Switch the direction -> rotates the sequence (1,0) (0,1) (-1,0) (0,-1)
tmp = dx; dx = -dy; dy = tmp;
// Reduce the next run length with one and switch dimensions
tmp = sideLen; sideLen = nextSideLen - 1; nextSideLen = tmp;
// Reset the side run counter
sideCounter = sideLen;
}
}
return result;
}
I solved by a simple solution which has almost the same performance of solution 2 as follows:
private static final int RIGHT_D = 1;
private static final int DOWN_D = 2;
private static final int LEFT_D = 3;
private static final int UP_D = 4;
private static Integer nextDir(Integer dir) {
if (dir == null || dir == UP_D) {
return RIGHT_D;
} else if (dir == RIGHT_D) {
return DOWN_D;
} else if (dir == DOWN_D) {
return LEFT_D;
} else if (dir == LEFT_D) {
return UP_D;
}
return null;
}
private static void moveCounters(Integer dir, int[][] arr) {
switch (dir) {
case RIGHT_D:
if (currentC 0) {
currentC–;
} else {
moveCounters(UP_D, arr);
}
break;
case DOWN_D:
if (currentR 0) {
currentR–;
} else {
moveCounters(RIGHT_D, arr);
}
break;
default:
}
}
private static int currentC = 0;
private static int currentR = 0;
public static List getSpiralMatrix(int arr[][]) {
if (arr == null) {
return null;
}
List output = new LinkedList();
if (arr[0].length == 1 && arr.length == 1) {
output.add(arr[0][0]);
return output;
}
Integer dir = null;
int visitedC = 0;
int visitedR = 0;
int nextTurnCounter = 0;
int noOfRows = arr.length;
int noOfCols = arr[0].length;
while (output.size() < noOfCols * noOfRows) {
dir = nextDir(dir);
if (dir == RIGHT_D || dir == LEFT_D) {
nextTurnCounter = noOfCols – visitedC;
} else {
nextTurnCounter = noOfRows – visitedR;
}
for (int i = 0; i < nextTurnCounter; i++) {
output.add(arr[currentR][currentC]);
moveCounters(dir, arr);
}
if (dir == RIGHT_D || dir == LEFT_D) {
visitedR++;
} else {
visitedC++;
}
}
return output;
}
I am sharing this code which I designed for a different purpose; it is about finding the Column number “X”, and the row number “Y” of array element @ spiral index “index”. Of course, this function can be used to produce the same required output. I think it is the fastest possible method (as it jumps over cells instead of scanning them), and it
rec BuildSpiralIndex(long w, long h, long index = -1)
{
long count = 0 , x = -1, y = -1, dir = 1, phase=0, pos = 0, length = 0, totallength = 0;
bool isVertical = false;
if(index>=(w*h)) return null;
do
{
isVertical = (count % 2) != 0;
length = (isVertical ? h : w) – count/2 – count%2 ;
totallength += length;
count++;
} while(totallength 1 ? phase : w – phase);
y = ((pos == 1 || pos == 2) ? h – phase : phase) + (1 * (pos == 3 ? 1 : 0));
dir = pos > 1 ? -1 : 1;
if (isVertical) y -= (totallength – index – 1) * dir;
else x -= (totallength – index -1) * dir;
return new rec { X = x, Y = y };
}
Thank you for your solutions.
But, I do believe that your recursive Solution #2 can be simplified a little. There are some checks in place that I think are unnecessary. I am posting my private helper function. I have unit-tested my solution using matrices of various sizes starting from 1×1 up to 5×4
private List spiral(final int[][] matrix, int currentRow, int currentCol, int rows, int cols) {
final List result = new ArrayList();
if (rows <= 0 || cols <= 0) {
return result;
}
//only one element left
if (rows == 1 && cols == 1) {
result.add(matrix[currentRow][currentCol]);
return result;
}
//Top side: Move from left to right
for (int idx = 0; idx < cols - 1 /* the '-1' is important, it will be the start of next loop */; idx++) {
result.add(matrix[currentRow][currentCol++]);
}
//Right side: Move from top to bottom
for (int idx = 0; idx < rows - 1 /* the '-1' is important*/; idx++) {
result.add(matrix[currentRow++][currentCol]);
}
//Bottom side: Move from right to left
for (int idx = 0; idx < cols - 1 /* the '-1' is important*/; idx++) {
result.add(matrix[currentRow][currentCol--]);
}
//Left side: Move from bottom to top
for (int idx = 0; idx < rows - 1 /* the '-1' is important*/; idx++) {
result.add(matrix[currentRow--][currentCol]);
}
// By the time we reached here, we finished walking the external 'circle',
// the currentRow & currentCol are back to zeroes.
//
// Now, we want to start walking the next inner circle, by incrementing
// currentRow & currentCol and adjusting the matrix limits
result.addAll(spiral(matrix, currentRow + 1, currentCol + 1, rows - 2, cols - 2));
return result;
}
Solution 1 is very neat and easy to understand. Thanks.
Hi
i just want to share my solution. I think it is more simple.
public static void spiralPrint(int arr[][]){
int m = arr.length;
int n = arr[0].length;
int i = 0;
int srow = 0; int erow = m – 1;
int scol = 0; int ecol = n – 1;
while(i < m*n){
for (int j = scol; j <= ecol; j++) {
System.out.print(arr[srow][j] + " ");
i++;
}
srow++;
for (int j = srow; j = scol; j–) {
System.out.print(arr[erow][j] + ” “);
i++;
}
erow–;
for (int j = erow; j >= srow; j–) {
System.out.print(arr[j][scol] + ” “);
i++;
}
scol++;
}
}
I will be happy to get a feedback.
Thanks
Just want to share a Python solution since it’s extremely simple:
def spiral_matrix(m):
result = []
while len(m) > 0:
result += m[0]
m = zip(*m[1:len(m)])[::-1]
return result
I reversed the for-loop increment after every row increment
public class Solution {
public ArrayList sprialOrder(int[][] matrix) {
ArrayList result = new ArrayList();
int row = matrix.length;
int col = matrix[0].length;
int rowIdx = 0;
while (result.size() < (row * col)) {
for (int colIdx = 0; colIdx = (row * col)) {
break;
}
rowIdx++; //down row
for (int colIdx = (col – 1); colIdx >= 0; colIdx–) {
result.add(matrix[rowIdx][colIdx]);
}
if (result.size() >= (row * col)) {
break;
}
rowIdx++; //down row
}
return result;
}
}
This is will provide the same functionality with complexity of O(m*n) where m and n are size of row and column
private static List spiralMatrix(int arr[][], int m, int n) {
List result = new ArrayList();
if (m <= 0 || n <= 0)
return result;
int i = 0, j = 0, m1 = 0, n1 = 0, m2 = m – 1, n2 = n – 1, flag = 0;
while (true) {
result.add(arr[i][j]);
if (flag == 0 && j == n2) {
m1++;
flag = (flag + 1) % 4;
} else if (flag == 1 && i == m2) {
n2–;
flag = (flag + 1) % 4;
} else if (flag == 2 && j == n1) {
m2–;
flag = (flag + 1) % 4;
} else if (flag == 3 && i == m1) {
n1++;
flag = (flag + 1) % 4;
}
if (flag == 0) {
j++;
} else if (flag == 1) {
i++;
} else if (flag == 2) {
j–;
} else if (flag == 3) {
i–;
}
if (i m2 || j n2) {
break;
}
}
return result;
}
This might be a little bit more concise, do not need to check if only one column or row left. already pass all tests.
public List spiralOrder(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return new ArrayList();
}
List result = new ArrayList();
int width = matrix[0].length, height = matrix.length, count = width * height, layer = 0;
while (count > 0) {
// top
for (int i = layer; count > 0 && i 0 && i 0 && i >= layer; i–) {
result.add(matrix[height – layer – 1][i]);
count –;
}
// left
for (int i = height – layer – 2; count > 0 && i > layer; i–) {
result.add(matrix[i][layer]);
count –;
}
layer ++;
}
return result;
}
Thank you for all these great algorithm solutions. I found the solutions you provided are really clear and short compared to other places. Keep posting it up.