forked from realpacific/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUniquePathsII.kt
152 lines (133 loc) · 4.91 KB
/
UniquePathsII.kt
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package questions
import _utils.UseCommentAsDocumentation
import utils.shouldBe
/**
* A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
* The robot can only move either down or right at any point in time.
* The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
* Now consider if some obstacles are added to the grids. How many unique paths would there be?
* An obstacle and space is marked as 1 and 0 respectively in the grid.
*
* <img src="https://assets.leetcode.com/uploads/2020/11/04/robot1.jpg" height="200" width="200"/>
*
* [Source](https://leetcode.com/problems/unique-paths-ii/)
*/
@UseCommentAsDocumentation
private interface UniquePathsII {
fun uniquePathsWithObstacles(obstacleGrid: Array<IntArray>): Int
}
private class UniquePathsIINaiveApproach : UniquePathsII {
private enum class Dir { R, D }
private var answer = 0
private lateinit var grid: Array<IntArray>
override fun uniquePathsWithObstacles(obstacleGrid: Array<IntArray>): Int {
if (obstacleGrid[obstacleGrid.lastIndex][obstacleGrid[0].lastIndex] == 1) {
return 0
}
if (obstacleGrid[0][0] == 1) {
return 0
}
this.grid = obstacleGrid
val m = obstacleGrid.size
val n = obstacleGrid[0].size
if (m == 1 && n == 1) return 1
traverse(Dir.R, 0, 0, m - 1, n - 1) // go right
traverse(Dir.D, 0, 0, m - 1, n - 1) // go down
return answer
}
private fun traverse(direction: Dir, posX: Int, posY: Int, rowMaxIndex: Int, colMaxIndex: Int) {
if (direction == Dir.R) {
val newPositionX = posX + 1
if (!canMoveHere(row = posY, col = newPositionX)) {
return
}
if (newPositionX == colMaxIndex && posY == rowMaxIndex) {
answer++
} else {
traverse(Dir.R, newPositionX, posY, rowMaxIndex, colMaxIndex)
traverse(Dir.D, newPositionX, posY, rowMaxIndex, colMaxIndex)
}
} else {
val newPositionY = posY + 1
if (!canMoveHere(row = newPositionY, col = posX)) {
return
}
if (posX == colMaxIndex && newPositionY == rowMaxIndex) {
answer++
} else {
traverse(Dir.R, posX, newPositionY, rowMaxIndex, colMaxIndex)
traverse(Dir.D, posX, newPositionY, rowMaxIndex, colMaxIndex)
}
}
}
private fun canMoveHere(row: Int, col: Int): Boolean {
val cell = this.grid.getOrNull(row)?.getOrNull(col)
if (cell == 0) return true
if (cell == 1 || cell == null) return false
return true
}
}
private class UniquePathsIINaiveArrayOfArray : UniquePathsII {
override fun uniquePathsWithObstacles(obstacleGrid: Array<IntArray>): Int {
if (obstacleGrid[obstacleGrid.lastIndex][obstacleGrid[0].lastIndex] == 1) {
return 0
}
if (obstacleGrid[0][0] == 1) {
return 0
}
val m = obstacleGrid.size
val n = obstacleGrid[0].size
val dp = Array<IntArray>(m) {
IntArray(n) { 0 }
}
for (row in 0..dp.lastIndex) {
for (col in 0..dp[0].lastIndex) {
if (obstacleGrid[row][col] == 1) {
dp[row][col] = 0
} else if (row == 0 && col == 0) {
dp[row][col] = 1 // only one way to get to (0,0) is moving left
} else if (row == 0) {
dp[row][col] = dp[row][col - 1] // only way to get to first row is move up
} else if (col == 0) {
dp[row][col] = dp[row - 1][col] // only way to get to left col is move left
} else {
dp[row][col] = dp[row - 1][col] + dp[row][col - 1] // two ways
}
}
}
return dp[m - 1][n - 1]
}
}
fun main() {
val uniquePathCheck: (input: Array<IntArray>, expected: Int) -> Int? = { input, expected ->
UniquePathsIINaiveApproach().uniquePathsWithObstacles(input) shouldBe
UniquePathsIINaiveArrayOfArray().uniquePathsWithObstacles(input) shouldBe expected
}
uniquePathCheck.invoke(arrayOf(intArrayOf(1, 0)), 0)
run {
val input = arrayOf(
intArrayOf(0, 0),
intArrayOf(1, 1),
intArrayOf(0, 0)
)
uniquePathCheck.invoke(input, 0)
}
uniquePathCheck.invoke(
arrayOf(
intArrayOf(0, 0, 0),
intArrayOf(0, 1, 0),
intArrayOf(0, 0, 0)
),
2
)
uniquePathCheck.invoke(
arrayOf(
intArrayOf(0, 0, 0, 0),
intArrayOf(0, 1, 0, 0),
intArrayOf(0, 0, 0, 0),
intArrayOf(0, 0, 1, 0),
intArrayOf(0, 0, 0, 0),
),
7
)
}