-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
124 lines (110 loc) · 3.45 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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
}