-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ad51ca3
commit 7fc184d
Showing
3 changed files
with
190 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package main | ||
|
||
import "math" | ||
|
||
// brute force will result in a time limit exceeded error | ||
func spiralOrder(matrix [][]int) []int { | ||
mixRow, mixCol := len(matrix), len(matrix[0]) | ||
result := make([]int, mixRow*mixCol) | ||
row, col := 0, 0 | ||
result[0] = matrix[row][col] | ||
visit := 101 | ||
matrix[row][col] = visit | ||
direction := [][]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}} | ||
for i := 1; i < len(result); { | ||
for j := 0; j < len(direction); { | ||
newRow, newCol := row+direction[j][0], col+direction[j][1] | ||
if newRow == mixRow || newCol == mixCol || | ||
newRow < 0 || newCol < 0 { | ||
j++ | ||
continue | ||
} | ||
|
||
if matrix[newRow][newCol] == visit { | ||
j++ | ||
continue | ||
} | ||
|
||
row, col = newRow, newCol | ||
result[i] = matrix[row][col] | ||
matrix[row][col] = visit | ||
i++ | ||
if i == len(result) { | ||
break | ||
} | ||
} | ||
} | ||
|
||
return result | ||
} | ||
|
||
// optimize spiralOrder | ||
// time complexity: O(M * N) this is because we visit each element once. | ||
// space complexity: O(1) | ||
// | ||
// if we mark the cells that we visited, then when we run into a visited cell, | ||
// we know we need to run. | ||
// | ||
// if `changeDirection` is larger than 1, it means we are continuously | ||
// changing our directions, and therefore we've visited all of the elements. | ||
// | ||
// modifying the original data may not be a good choice sometimes. therefore, | ||
// we can also prepare another boolean matrix to store the cells we visited. | ||
// however, the implementation of this approach is quite similar. | ||
func spiralOrder2(matrix [][]int) []int { | ||
m, n := len(matrix), len(matrix[0]) | ||
row, col := 0, 0 | ||
result := make([]int, 0, m*n) | ||
visit := 101 | ||
result = append(result, matrix[row][col]) | ||
matrix[row][col] = visit | ||
|
||
directions := [4][2]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}} | ||
currentDirection := 0 | ||
changeDirection := 0 | ||
|
||
for changeDirection < 2 { | ||
for row+directions[currentDirection][0] >= 0 && | ||
row+directions[currentDirection][0] < m && | ||
col+directions[currentDirection][1] >= 0 && | ||
col+directions[currentDirection][1] < n && | ||
matrix[row+directions[currentDirection][0]][col+directions[currentDirection][1]] != visit { | ||
row += directions[currentDirection][0] | ||
col += directions[currentDirection][1] | ||
result = append(result, matrix[row][col]) | ||
matrix[row][col] = visit | ||
|
||
// reset this to 0 since we did not break and change the direction | ||
changeDirection = 0 | ||
} | ||
// change our direction | ||
currentDirection = (currentDirection + 1) % 4 | ||
// increment changeDirection because we changed our direction | ||
changeDirection++ | ||
} | ||
|
||
return result | ||
} | ||
|
||
// set up boundaries | ||
// time complexity: O(M * N) | ||
// space complexity: O(1) | ||
|
||
// there are only two movement pattern, right + down and left + up. | ||
// in the first case we increment either the row or column by 1, and | ||
// in the latter case we increment either the row or column by -1. | ||
// also notice that after we move horizontally the number of possible | ||
// vertical steps decrease by 1, and after we move vertically the number | ||
// of possible horizontal steps decrease by 1. when we run out of either | ||
// vertical steps or horizontal steps we reach the end. | ||
func spiralOrder3(matrix [][]int) []int { | ||
m, n := len(matrix), len(matrix[0]) | ||
direction := 1 | ||
row, col := 0, -1 | ||
result := []int{} | ||
for math.Min(float64(m), float64(n)) != 0 { | ||
// move horizontally | ||
for i := 0; i < n; i++ { | ||
col += direction | ||
result = append(result, matrix[row][col]) | ||
} | ||
m -= 1 | ||
|
||
// move vertically | ||
for i := 0; i < m; i++ { | ||
row += direction | ||
result = append(result, matrix[row][col]) | ||
} | ||
n -= 1 | ||
|
||
// flip direction | ||
direction *= -1 | ||
} | ||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestSpiralOrder(t *testing.T) { | ||
for _, tt := range []struct { | ||
matrix [][]int | ||
want []int | ||
}{{ | ||
matrix: [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, | ||
want: []int{1, 2, 3, 6, 9, 8, 7, 4, 5}, | ||
}, { | ||
matrix: [][]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, | ||
want: []int{1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7}, | ||
}, { | ||
matrix: [][]int{{8, 9, 4, 1, 2, 5}, {10, 19, 32, 14, 3, 6}}, | ||
want: []int{8, 9, 4, 1, 2, 5, 6, 3, 14, 32, 19, 10}, | ||
}, { | ||
matrix: [][]int{{-10, 0, -7}, {0, 9, -100}}, | ||
want: []int{-10, 0, -7, -100, 9, 0}, | ||
}} { | ||
matrix1 := shallowCopy2DSlice(tt.matrix) | ||
got := spiralOrder(matrix1) | ||
if !equal(tt.want, got) { | ||
t.Errorf("got: %v, want: %v", got, tt.want) | ||
} | ||
|
||
matrix2 := shallowCopy2DSlice(tt.matrix) | ||
got = spiralOrder2(matrix2) | ||
if !equal(tt.want, got) { | ||
t.Errorf("got: %v, want: %v", got, tt.want) | ||
} | ||
|
||
matrix3 := shallowCopy2DSlice(tt.matrix) | ||
got = spiralOrder3(matrix3) | ||
if !equal(tt.want, got) { | ||
t.Errorf("got: %v, want: %v", got, tt.want) | ||
} | ||
} | ||
} | ||
|
||
func shallowCopy2DSlice(matrix [][]int) [][]int { | ||
shallow := make([][]int, len(matrix)) | ||
for i := range matrix { | ||
arr := make([]int, len(matrix[i])) | ||
copy(arr, matrix[i]) | ||
shallow[i] = arr | ||
} | ||
return shallow | ||
} | ||
|
||
func equal(expect, actual []int) bool { | ||
if len(expect) != len(actual) { | ||
return false | ||
} | ||
for i := 0; i < len(expect); i++ { | ||
if expect[i] != actual[i] { | ||
return false | ||
} | ||
} | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters