Skip to content

Commit 7e59bd7

Browse files
committed
Added task 864.
1 parent e2eebc9 commit 7e59bd7

File tree

2 files changed

+114
-0
lines changed
  • src
    • main/kotlin/g0801_0900/s0864_shortest_path_to_get_all_keys
    • test/kotlin/g0801_0900/s0864_shortest_path_to_get_all_keys

2 files changed

+114
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package g0801_0900.s0864_shortest_path_to_get_all_keys
2+
3+
import java.util.*
4+
5+
class Solution {
6+
private var m = 0
7+
private var n = 0
8+
fun shortestPathAllKeys(stringGrid: Array<String>): Int {
9+
// strategy: BFS + masking
10+
m = stringGrid.size
11+
n = stringGrid[0].length
12+
val grid = Array(m) { CharArray(n) }
13+
var index = 0
14+
// convert to char Array
15+
for (s in stringGrid) {
16+
grid[index++] = s.toCharArray()
17+
}
18+
// number of keys
19+
var count = 0
20+
val q: Queue<IntArray> = LinkedList()
21+
for (i in 0 until m) {
22+
for (j in 0 until n) {
23+
// find starting position
24+
if (grid[i][j] == '@') {
25+
q.add(intArrayOf(i, j, 0))
26+
}
27+
// count number of keys
28+
if (grid[i][j] in 'a'..'f') {
29+
count++
30+
}
31+
}
32+
}
33+
val dx = intArrayOf(-1, 0, 1, 0)
34+
val dy = intArrayOf(0, -1, 0, 1)
35+
// this is the amt of keys we need
36+
val target = (1 shl count) - 1
37+
// keep track of position and current state
38+
val visited = Array(m) {
39+
Array(n) {
40+
BooleanArray(target + 1)
41+
}
42+
}
43+
// set initial position and state to true
44+
visited[q.peek()[0]][q.peek()[1]][0] = true
45+
var steps = 0
46+
while (!q.isEmpty()) {
47+
// use size to make sure everything is on one level
48+
var size = q.size
49+
while (--size >= 0) {
50+
val curr = q.poll()
51+
val x = curr[0]
52+
val y = curr[1]
53+
val state = curr[2]
54+
// found all keys
55+
if (state == target) {
56+
return steps
57+
}
58+
for (i in 0..3) {
59+
val nx = x + dx[i]
60+
val ny = y + dy[i]
61+
// use new state so we don't mess up current state
62+
var nState = state
63+
// out of bounds or reached wall
64+
if (!inBounds(nx, ny) || grid[nx][ny] == '#') {
65+
continue
66+
}
67+
// found key
68+
// use OR to add key to our current state because if we already had the key the
69+
// digit would still be 1/true
70+
if (grid[nx][ny] in 'a'..'f') {
71+
// bit mask our found key
72+
nState = state or (1 shl grid[nx][ny] - 'a')
73+
}
74+
// found lock
75+
// use & to see if we have the key
76+
// 0 means that the digit we are looking at is 0
77+
// need a 1 at the digit spot which means there is a key there
78+
if (('A' > grid[nx][ny] || grid[nx][ny] > 'F' || nState and (1 shl grid[nx][ny] - 'A') != 0)
79+
&& !visited[nx][ny][nState]
80+
) {
81+
q.add(intArrayOf(nx, ny, nState))
82+
visited[nx][ny][nState] = true
83+
}
84+
}
85+
}
86+
steps++
87+
}
88+
return -1
89+
}
90+
91+
private fun inBounds(x: Int, y: Int): Boolean {
92+
return x in 0 until m && y >= 0 && y < n
93+
}
94+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package g0801_0900.s0864_shortest_path_to_get_all_keys
2+
3+
import org.hamcrest.CoreMatchers.equalTo
4+
import org.hamcrest.MatcherAssert.assertThat
5+
6+
import org.junit.Test
7+
8+
internal class SolutionTest {
9+
@Test
10+
fun shortestPathAllKeys() {
11+
val solution = Solution()
12+
assertThat(
13+
solution.shortestPathAllKeys(arrayOf("@.a.#", "###.#", "b.A.B")), equalTo(8)
14+
)
15+
assertThat(
16+
solution.shortestPathAllKeys(arrayOf("@..aA", "..B#.", "....b")), equalTo(6)
17+
)
18+
assertThat(solution.shortestPathAllKeys(arrayOf("@Aa")), equalTo(-1))
19+
}
20+
}

0 commit comments

Comments
 (0)