字母迷宫

153 阅读2分钟

题目:给定一个n*m的矩阵,矩阵仅由字母 r , d , e 组成,你可以走上、下、左、右四个方向,每次走一格,但字母迷宫有如下限制:

  • 如当前所在格子的字母为 r,那么你将无法前往 d
  • 如当前所在格子的字母为 d,那么你将无法前往 e
  • 如当前所在格子的字母为 e,那么你将无法前往 r

请问你能否在这种情况下从(1,1)走到(n,m),若能输出最小步数,若不能,输出-1。

样例1:
输入
2 2
r e
d d
输出:2

样例2:
输入
3 4
r d e r
e r d d
d r e r
输出:7

解题思路:图论BFS的题目。主要运用队列和记忆化搜的知识去解决。队列储存着我们目前要扩展的点(已经访问,但是没有访问它的周围点)。而BFS有个特点,那就是第一次访问点(x, y)所需要走的路径必然是最少的,所以记忆化搜可以配合BFS的特点,可以很好求到每个被访问点的最短路径。

class Node {
  constructor(data) {
    this.data = data;
    this.next = null;
  }
}

class LinkedList {
  constructor() {
    this.length = 0;
    this.head = null;
  }

  append(data) {
    var newNode = new Node(data);
    if (this.length == 0) {
      this.head = newNode;
    } else {
      var current = this.head;
      while (current && current.next) {
        current = current.next;
      }
      current.next = newNode;
    }
    this.length += 1;
  }

  isEmpty() {
    return this.head === null;
  }

  poll() {
    var current = this.head;
    this.head = this.head.next;
    this.length -= 1;
    return current;
  }
}

class TwoTuple {
  constructor(a, b) {
    this.first = a;
    this.second = b;
  }
}

const main = (n, m, mp) => {
  let vis = new Array(n).fill(-1).map(() => new Array(m).fill(-1));

  // 表示上下左右四个方向
  let fx = [0, 1, 0, -1];
  let fy = [1, 0, -1, 0];

  const isok = (x, y, last) => {
    if (x >= 0 && x < n && y >= 0 && y < m && vis[x][y] === -1) {
      // 没有被访问过的点
      if ((mp[x][y] !== 'r' && last === 'e') || (mp[x][y] !== 'd' && last === 'r') || (mp[x][y] !== 'e' && last === 'd')) {
        return true;
      }
    }
    return false;
  };

  let q = new LinkedList();
  q.append(new TwoTuple(0, 0));

  // 第一个路径是0
  vis[0][0] = 0;

  while (!q.isEmpty()) {
    let now = q.poll().data;

    for (let i = 0; i < 4; i++) {
      let xx = now.first + fx[i];
      let yy = now.second + fy[i];

      if (isok(xx, yy, mp[now.first][now.second])) {
        // 向四周扩散
        q.append(new TwoTuple(xx, yy)); // 如果这个点没有被访问过 那就扩展它
        vis[xx][yy] = vis[now.first][now.second] + 1;
      }
    }
  }

  return vis[n - 1][m - 1];
};
main(2, 2, [
  ['r', 'e'],
  ['d', 'd']
]); // 2
main(3, 4, [
  ['r', 'd', 'e', 'r'],
  ['e', 'r', 'd', 'd'],
  ['d', 'r', 'e', 'r']
]); // 7