-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy pathShortest Path to Get All Keys.js
154 lines (143 loc) · 3.95 KB
/
Shortest Path to Get All Keys.js
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
153
154
// Runtime: 208 ms (Top 67.74%) | Memory: 64.90 MB (Top 80.65%)
/**
* @param {string[]} grid
* @return {number}
*/
var shortestPathAllKeys = function(grid)
{
const rows = grid.length, cols = grid[0].length, INF = Number.MAX_SAFE_INTEGER-1;
/* Find the locks and keys */
let keyChars = '', start;
for(let i=0; i<rows; i++)
{
for(let j=0; j<cols; j++)
{
let letter = grid[i][j];
if(letter === '@')
{
start = [i,j];
continue;
}
if(letter === '.' || letter === '#')
continue;
if(letter >= 'a')
keyChars += letter;
}
}
let lockChars = keyChars.toUpperCase();
const combos = Math.pow(2,keyChars.length);
let mask = 0x01, bitPos = {}, unlocks = {};
for(let i=0; i<keyChars.length; i++)
{
bitPos[keyChars[i]] = mask;
unlocks[lockChars[i]] = mask;
mask *= 2;
}
let dp = Array(rows);
for(let i=0; i<rows; i++)
{
dp[i] = Array(cols);
for(let j=0; j<cols; j++)
dp[i][j] = Array(combos).fill(INF);
}
dp[start[0]][start[1]][0] = 0;
//console.log(dp);
//console.log(bitPos, unlocks);
const getNeighbors = function(r, c)
{
let neighbors = [];
if(r > 0)
neighbors.push([r-1,c]);
if(r < rows-1)
neighbors.push([r+1,c]);
if(c > 0)
neighbors.push([r,c-1]);
if(c < cols-1)
neighbors.push([r,c+1]);
return neighbors;
};
/**** SMUSH functions to "smush" through the various terrain ****/
const smushWall = (r,c,prev) => false;
const smushSpace = function(r,c,prev)
{
let changed = false;
for(let i=0; i<prev.length; i++)
{
if(dp[r][c][i] > prev[i]+1)
{
dp[r][c][i] = prev[i]+1;
changed = true;
}
}
return changed;
};
const smushKeyFunc = function(key)
{
let mask = bitPos[key];
const smushKey = function(r,c,prev)
{
let changed = false;
for(let i=0; i<prev.length; i++)
{
if(dp[r][c][i|mask] > prev[i]+1)
{
dp[r][c][i|mask] = prev[i]+1;
changed = true;
}
}
return changed;
}
return smushKey;
};
const smushLockFunc = function(key)
{
let mask = unlocks[key];
const smushLock = function(r,c,prev)
{
let changed = false;
for(let i=0; i<prev.length; i++)
{
if((i & mask) !== mask)
continue;
if(dp[r][c][i] > prev[i]+1)
{
dp[r][c][i] = prev[i]+1;
changed = true;
}
}
return changed;
}
return smushLock;
};
let smush = {'#':smushWall, '.':smushSpace, '@':smushSpace};
for(let i=0; i<keyChars.length; i++)
{
smush[keyChars[i]] = smushKeyFunc(keyChars[i]);
}
for(let i=0; i<lockChars.length; i++)
{
smush[lockChars[i]] = smushLockFunc(lockChars[i]);
}
let minPath = INF, buf = [start];
while(buf.length > 0)
{
let next = new Set();
for(let [r,c] of buf)
{
let neighbors = getNeighbors(r,c);
for(let [nrow,ncol] of neighbors)
{
if(smush[grid[nrow][ncol]](nrow, ncol, dp[r][c]))
{
if(dp[nrow][ncol][dp[nrow][ncol].length-1] < INF)
minPath = Math.min(minPath, dp[nrow][ncol][dp[nrow][ncol].length-1]);
else
next.add([nrow,ncol]);
}
}
}
buf = [...next];
}
//console.log(bitPos);
return (minPath === INF) ? -1 : minPath;
};