活跃农民
- 积分
- 509
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2013-6-5
- 最后登录
- 1970-1-1
|
0114 The Maze III
/**
* @param {number[][]} maze
* @param {number[]} ball
* @param {number[]} hole
* @return {string}
*/
var findShortestWay = function(maze, ball, hole) {
// !!! this is a shortest path problem
// 1. if is unweighted graph, use BFS (in this case just degenerated Dijkstra)
// 2. if is weighted graph, use Dijkstra,
// consult the maze II, why BFS has the same complexity as DFS? Because this kind of problems are weighted graph, so you
// cannot just use BFS to solve it fast. You need to use Dijkstra. Thus using BFS you just brute force search, which is the
// same as DFS.
// use dijkistra with pq
// now the challenge is: 1. stop at any time, that's not too difficult,
// 2. need to get the path. how? need to backtrack since we are not using dfs.
// need to keep a backtrack map
// for each node, keep the smallest path to this current node using the prev map.
// but they don't want the node path, they want the direction path, we could still get it, but is there a way to get it directly? we store the complete path on each node? that is also doable.
class Heap {
constructor (data, compare) {
this.data = data || []
this.compare = compare || ((a, b) => a - b);
const lastParent = this.getParent(this.data.length - 1);
for (let i = lastParent; i >= 0; i--) {
this.siftDown(i);
}
}
getParent (i) {
return Math.trunc((i - 1) / 2);
}
swap (i, j) {
;[this.data[i], this.data[j]] = [this.data[j], this.data[i]];
}
siftDown (i) {
let min = i;
const left = 2 * i + 1;
const right = 2 * i + 2;
for (let index of [left, right]) {
if (index < this.data.length && this.compare(this.data[index], this.data[min]) < 0) {
min = index;
}
}
if (min !== i) {
this.swap(min, i);
this.siftDown(min);
}
}
siftUp (i) {
const parent = this.getParent(i);
if (this.compare(this.data[i], this.data[parent]) < 0) {
this.swap(parent, i);
this.siftUp(parent);
}
}
push (val) {
this.data.push(val);
this.siftUp(this.data.length - 1);
}
get size () {
return this.data.length;
}
peak () {
return this.data[0];
}
pop () {
if (this.size === 0) {return undefined}
const val = this.peak();
this.swap(0, this.data.length - 1);
this.data.pop();
this.siftDown(0);
return val;
}
}
if (maze == null || maze.length === 0) {
return 'impossible';
}
const rowLen = maze.length;
const colLen = maze[0].length;
const dist = Array(rowLen).fill().map(() => Array(colLen).fill(Infinity));
const path = Array(rowLen).fill().map(() => Array(colLen).fill('z')); // !!! init to z for infinity
dist[ball[0]][ball[1]] = 0;
path[ball[0]][ball[1]] = '';
const compare = (dist1, path1, dist2, path2) => {
if (dist1 === dist2) {
if (path1 < path2) {
return -1;
} else if (path1 > path2) {
return 1
} else {
return 0;
}
} else {
return dist1 - dist2;
}
}
const heap = new Heap([], (a, b) => compare(a[2], a[3], b[2], b[3]));
heap.push([...ball, 0, '']); // !!! have 4 els now
while (heap.size > 0) {
const [x, y, aDist, aPath] = heap.pop();
if (compare(aDist, aPath, dist[x][y], path[x][y]) > 0) {continue;}
const moves = [[0, 1, 'r'], [0, -1, 'l'], [1, 0, 'd'], [-1, 0, 'u']];
for (let [dx, dy, dir] of moves) {
let newX = x;
let newY = y;
let newDist = aDist;
// !!! all newX + dx, newY + dy
let found = false;
while (newX + dx >= 0 && newX + dx < rowLen && newY + dy >= 0 && newY + dy < colLen && maze[newX + dx][newY + dy] === 0) {
newX += dx;
newY += dy;
newDist++;
// !!!!! cannot just stop here, because you not only need to find it, but you need to find the lexically smallest
// but you need to test here
if (newX === hole[0] && newY === hole[1]) {
found = true;
break;
}
}
// 1. compare the dist; 2. if that equal, compare the path
const newPath = path[x][y] + dir;
if (compare(newDist, newPath, dist[newX][newY], path[newX][newY]) < 0) { // !!!newX, newY not x, y in the 2d array !!!!
// !!! that's because we are comparing with the prev value of same point, not values of this and prev point
dist[newX][newY] = newDist;
path[newX][newY] = newPath;
if (!found) {
heap.push([newX, newY, newDist, newPath]);
}
}
}
}
const val = path[hole[0]][hole[1]];
return val === 'z' ? 'impossible' : val;
}; |
|