【LeetCode】每日一题 面试题 16.22. 兰顿蚂蚁

194 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

面试题 16.22. 兰顿蚂蚁

一只蚂蚁坐在由白色和黑色方格构成的无限网格上。开始时,网格全白,蚂蚁面向右侧。每行走一步,蚂蚁执行以下操作。

(1) 如果在白色方格上,则翻转方格的颜色,向右(顺时针)转 90 度,并向前移动一个单位。 (2) 如果在黑色方格上,则翻转方格的颜色,向左(逆时针方向)转 90 度,并向前移动一个单位。

编写程序来模拟蚂蚁执行的前 K 个动作,并返回最终的网格。

网格由数组表示,每个元素是一个字符串,代表网格中的一行,黑色方格由 'X' 表示,白色方格由 '_' 表示,蚂蚁所在的位置由 'L', 'U', 'R', 'D' 表示,分别表示蚂蚁 左、上、右、下 的朝向。只需要返回能够包含蚂蚁走过的所有方格的最小矩形。

「示例1:」
输入: 0
输出: ["R"]
「示例2:」
输入: 2
输出:
[
  "_X",
  "LX"
]
「示例3:」
输入: 5
输出:
[
  "_U",
  "X_",
  "XX"
]
「提示:」
K <= 100000

解题思路

用minX, maxX, minY, maxY保存蚂蚁走过的边界
用dp保存蚂蚁走过的位置的砖块
用blackSet保存黑色方块的位置
​
蚂蚁走的话只有以下几种情况
当前位置 x, y
​
当前位置是白色砖块,当前方向是右 -> 砖块变黑,方向变成下,走一步变成 x + 1, y
当前位置是白色砖块,当前方向是左 -> 砖块变黑,方向变成上,走一步变成 x - 1, y
当前位置是白色砖块,当前方向是上 -> 砖块变黑,方向变成右,走一步变成 x, y + 1
当前位置是白色砖块,当前方向是下 -> 砖块变黑,方向变成左,走一步变成 x, y - 1
当前位置是黑色砖块,当前方向是右 -> 砖块变白,方向变成上,走一步变成 x - 1, y
当前位置是黑色砖块,当前方向是左 -> 砖块变白,方向变成下,走一步变成 x + 1, y
当前位置是黑色砖块,当前方向是上 -> 砖块变白,方向变成左,走一步变成 x, y - 1
当前位置是黑色砖块,当前方向是下 -> 砖块变白,方向变成右,走一步变成 x, y + 1
更新边界
更新蚂蚁当前位置的砖块
​
最后将边界内的内容拼凑成结果

代码实现

/**
 * @param {number} K
 * @return {string[]}
 */
var printKMoves = function(K) {
  const dp = {}, position = [0, 0], 
  // 蚂蚁行进的位置
  positions = {
      'R': [0, 1],
      'L': [0, -1],
      'U': [-1, 0],
      'D': [1, 0],
  },
  // 蚂蚁在当前位置砖块颜色和方向的转换
  transform = {
      'R': {
          '_': ['D', 'X'],
          'X': ['U', '_']
      },
      'L': {
          '_': ['U', 'X'],
          'X': ['D', '_']
      },
      'U': {
          '_': ['R', 'X'],
          'X': ['L', '_']
      },
      'D': {
          '_': ['L', 'X'],
          'X': ['R', '_']
      },
  },
  blackSet = new Set
  let minX = 0, maxX = 0, minY = 0, maxY = 0, direction = 'R'
​
  // 获取蚂蚁走过的边界
  function getLimit(x, y) {
      minX = Math.min(x, minX)
      maxX = Math.max(x, maxX)
      minY = Math.min(y, minY)
      maxY = Math.max(y, maxY)
  }
  dp[position[0]] = []
  dp[position[0]][position[1]] = '_'
  let l = 0
  while(l < K) {
      // 现根据当前位置,取得当前位置的砖块颜色和方向,根据当前位置的砖块颜色和方向转换颜色和方向
      const [x, y] = position, d = direction, p = dp[x][y], cache = transform[d][p]
      direction = cache[0]
      dp[x][y] = cache[1]
​
      if (dp[x][y] === '_') {
          blackSet.delete(`${x}&${y}`)
      } else {
          blackSet.add(`${x}&${y}`)
      }
​
      // 根据转换的颜色和方向取得下一个位置的左边,和下一个位置的砖块颜色,以及蚂蚁行进的边界
      position[0] += positions[direction][0]
      position[1] += positions[direction][1]
​
      const [newx, newy] = position
      if (!dp[newx] || !dp[newx][newy]) {
            dp[newx] = dp[newx] || []
            dp[newx][newy] = '_'
      }
      getLimit(newx, newy)
      l++
  }
  // 根据蚂蚁的边界取得结果
  const res = Array(maxX - minX + 1)
    .fill(0)
    .map(() => Array(maxY - minY + 1).fill('_'))
  for (const pos of blackSet) {
    const [x, y] = pos.split('&')
    res[x - minX][y - minY] = 'X'
  }
  res[position[0] - minX][position[1] - minY] = direction
  return res.map((row) => row.join(''))
};

如果你对这道题目还有疑问的话,可以在评论区进行留言;