老师,推箱子这道题, 箱子从源点到目标点最少步数,显而易见是BFS方法去做,但是加了人去推动箱子,我就没辙了,看了官方题解,也没懂,可以讲下思路吗: )
==========================================================
老师,你讲的 【人,箱子】作为一个图节点,这个我懂了,然后我写了下面的代码,没写完,因为 当取出queue队列的节点后,
即当前节点, [nowPlayerR, nowPlayerC, nowBoxR, nowBoxC], 然后目前只有一个dirs列表线索,我要怎么取得当前节点的相邻节点?
===============================
老师,整个逻辑我都写在下面了,没通过,我自己也没想法了,能从我的代码里看出是哪里出了问题吗。。。。
/**
* @param {character[][]} grid
* @return {number}
*/
var minPushBox = function(grid) {
const dirs = [ [1, 0], [-1, 0], [0, 1], [0, -1] ];
let playerR, playerC, boxR, boxC, targetR, targetC;
for( let r = 0; r < grid.length; r ++ ){
for( let c = 0; c < grid[0].length; c ++ ){
if( grid[r][c] == 'S' ){ // 玩家 player
playerR = r;
playerC = c;
grid[r][c]='.'
}else if( grid[r][c] == 'B' ){ // 箱子 Box
boxR = r;
boxC = c;
grid[r][c]='.'
}else if( grid[r][c] == 'T' ){ // 目标位置Target
targetR = r;
targetC = c;
grid[r][c]='.'
}
} // for c
} // for r
let queue = []; // bfs队列
let visited = {}; // [人, 箱子]是否访问过 查找表
let step={}; // 统计步数
let res = 0; // 最终答案
queue.push( [playerR, playerC, boxR, boxC] );
visited[`${playerR}-${playerC}-${boxR}-${boxC}`] = true;
step[`${playerR}-${playerC}-${boxR}-${boxC}`] = 0;
while( queue.length > 0 ){
let [nowPlayerR, nowPlayerC, nowBoxR, nowBoxC] = queue.shift(); // 出队列
if( nowBoxR == targetR && nowBoxC == targetC ){ // 说明箱子被推到了目的地
//
return step[`${nowPlayerR}-${nowPlayerC}-${nowBoxR}-${nowBoxC}`]; // 返回
}
// 接下来要得到 [nowPlayerR, nowPlayerC, nowBoxR, nowBoxC]的相邻状态 ???, 要怎么得到
for( let i = 0; i < 4; i ++ ){
let nextPlayerR = nowPlayerR + dirs[i][0], nextPlayerC = nowPlayerC + dirs[i][1];
if( !isInArea(grid, nextPlayerR, nextPlayerC) ){
continue;
}
// 查看玩家目前是否走到了箱子的位置,如果是,则就可以推动箱子, 然后推完后,再次检查箱子的位置是否合法
if( nextPlayerR == nowBoxC && nextPlayerC == nowBoxC ){
let nextBoxR = nowBoxR + dirs[i][0];
let nextBoxC = nowBoxC + dirs[i][1];
// 箱子位置是否合法
if( !isInArea(grid, nextBoxR, nextBoxC) ){
continue;
}
// 检查 [nextPlayerR, nextPlayerC, nextBoxR, nextBoxC]之前有没有考察过
if( visited[`${nextPlayerR}-${nextPlayerC}-${nextBoxR}-${nextBoxC}`] ){
continue;
}
// 进队列
queue.push( [nextPlayerR, nextPlayerC, nextBoxR, nextBoxC] );
visited[`${nextPlayerR}-${nextPlayerC}-${nextBoxR}-${nextBoxC}`] = true; // 更新查找表
step[`${nextPlayerR}-${nextPlayerC}-${nextBoxR}-${nextBoxC}`] = step[`${nowPlayerR}-${nowPlayerC}-${nowBoxR}-${nowBoxC}`] + 1; // 更新步数
}else{
// 说明人和箱子间有距离,人还没够着箱子
// 检查 [nextPlayerR, nextPlayerC, nowBoxR, nowBoxC]之前有没有考察过
if( visited[`${nextPlayerR}-${nextPlayerC}-${nowBoxR}-${nowBoxC}`] ){
continue;
}
// 进队列
queue.push( [nextPlayerR, nextPlayerC, nowBoxR, nowBoxC] );
visited[`${nextPlayerR}-${nextPlayerC}-${nowBoxR}-${nowBoxC}`] = true; // 更新查找表
step[`${nextPlayerR}-${nextPlayerC}-${nowBoxR}-${nowBoxC}`] = step[`${nowPlayerR}-${nowPlayerC}-${nowBoxR}-${nowBoxC}`] + 1; // 更新步数
}
} // for i dirs
} // end while queue.length > 0
return -1; // 说明无法做到
};
function isInArea( grid, r, c ){
if( r < 0 || r >= grid.length ){
return false;
}
if( c < 0 || c >= grid[0].length ){
return false;
}
return grid[r][c] == '.'
}