宽度优先遍历解决递归决策 抵达数组最后一个位置的最少步数

93 阅读1分钟

题目

image.png

  • 从 0 位置出发,每个位置都可能去往多个位置,记录下一层的位置,来到下一层时步数+1,遍历下一层查看是否抵达最后一个位置,如果抵达返回步数,如果没有继续记录一下层的所有位置,然后来到下一层
  • 比常规的宽度优先遍历多了一个记录下一层终止位置的步骤,通过决策下一步能来到的所有位置,查看是否满足条件

cfa12969ad4ae39a7cd947f47f8a61dd.png

image.png

function process(arr) {
  const map = new Map();
  // 记录某个元素出现的所有位置
  for (let i = 0; i <= arr.length; i++) {
    if (!map.get(arr[i])) {
      map.set(arr[i], [i]);
    } else {
      map.set(arr[i], map.get(arr[i]).push(i));
    }
  }
  // 已经抵达的位置不需要继续遍历,因为步骤一定比之前的多
  const visited = Array(arr.length).fill(false);
  const queue = Array(arr.length);
  let left = 0,
    right = 0;
  // 把 0 位置加到队列,从0开始宽度优先遍历
  queue[right++] = 0;
  visited[0] = true;
  let jump = 0;

  while (left !== right) {
    // 记录当前层的终止位置
    let temp = right;

    // 遍历当前层
    for (; left < temp; left++) {
      let current = queue[left];
      // 如果来到了数组最后一个位置
      if (current === arr.length - 1) {
        return jump;
      }
      // 往右位置
      if (current + 1 < arr.length && !visited[current + 1]) {
        visited[current + 1] = true;
        queue[right++] = current + 1;
      }
      // 往左位置
      if (current > 0 && !visited[current - 1]) {
        visited[current - 1] = true;
        queue[right++] = current - 1;
      }
      // 往值相同元素的位置
      for (let i = 0; i < map.get(arr[i]).length; i++) {
        let tempIndex = map.get(arr[i])[i];
        if (!visited[tempIndex]) {
          visited[tempIndex] = true;
          queue[right++] = tempIndex;
        }
      }
      map.delete(arr[i]);
    }
    jump++;
  }

  return -1;
}