青训营X豆包MarsCode 技术训练营 | 豆包MarsCode AI 刷题:我好想逃却逃不掉

90 阅读5分钟

1. 问题描述:曾经的我不过是一介草民,混迹市井,默默无名。直到我被罗马的士兵从家乡捉走丢进竞技场。对手出现了,我架紧盾牌想要防御,只觉得巨大的冲击力有如一面城墙冲涌而来,击碎了我的盾牌,我两眼发昏,沉重的身躯轰然倒地。我好想逃。但罗马最大的竞技场,哪有这么容易逃得掉工程师们早就在地上装了传送机关,虽不会伤人,却会将站在上面的人传到它指向的位置。若是几个传送机关围成一个环,不小心踩在上面的人就会被 围圈地反复传送.…想到这里,我不由得打了个寒额。必须避开这些危险的地方!在一个NxM的竞技场迷官中,你的任务是找出在迷官中,所有”危险位置”的数量。“危险位置”定义为:如果站在该位置上,无论采取什么移动策略,都无法到达出口。

竞技场中包含以下几种元素:

.:表示普通地板,可以自由移动到上下左右相邻的格子(不可以走斜线)

O:表示出口

U:表示向上的传送器,踩上去会被强制传送到上方的格了

D:表示向下的传送器,踩上去会被强制传送到下方的格子

L:表示向左的传送器,踩上去会被强制传送到左方的格子

R:表示向右的传送器,踩上去会被强制传送到右方的格子

注意,如果被传送出了竟技场之外,则算作死亡。

2. 问题分析:这是一个N×M的迷宫,字符含义:‘.’ 表示普通格子,‘O’ 表示出口,‘U’(上), ‘D’(下), ‘L’(左), ‘R’(右) 表示传送机关。当玩家踩到传送机关时,会被强制传送到指定方向的下一个格子。"环"指的是几个传送机关首尾相连,比如:→↓←↑ 这样形成一个循环。任务是找出迷宫中哪些位置存在环(循环)。

1) 问题理解: 首先,我认真分析了题目描述,明确了需要找出迷宫中所有无法到达出口的“危险位置”。这要求我不仅要处理普通地砖的移动,还要处理传送机关的强制移动以及由此产生的循环问题。

2) 数据结构选择: 在将输入数据转换成迷宫矩阵的过程中,可以使用列表来存储每一行的数据。通过判断每一行的类型,确保数据的一致性,为后续处理奠定基础。

3) 方向表示: 可以使用字典来表示移动方向,这不仅简化了代码,也提高了代码的可读性。这种表示方法在处理复杂方向问题时非常有效。

4) 递归搜索: 在实现移动策略时,可以使用了递归函数来检查从某一位置是否能够到达出口。递归是处理这类搜索问题的常用方法,它使得代码更加简洁。

5) 循环检测: 为了检测传送机关形成的循环,使用了一个集合来记录已经访问过的位置。如果再次访问到这些位置,说明存在循环,从而无法到达出口。

6) 边界条件处理: 在搜索过程中,需要留意边界条件,如越界和循环,这些都是导致无法到达出口的直接因素。

7) 结果统计: 最后,可以通过遍历迷宫的每一个位置,统计无法到达出口的位置数量。这一步骤是解题的核心,它直接给出了问题的答案。

3. 逻辑思路:

(1)构建N×M的矩阵

for row in data:

        if isinstance(row, str):

            maze.append(list(row))

        else:

            maze.append(row)

(2)上下左右方向移动表示

directions = {

        'U': (-1, 0),  # 上

        'D': (1, 0),   # 下

        'L': (0, -1),  # 左

        'R': (0, 1)    # 右

    }

(3)特定位置路线

if maze[start_x][start_y] in directions:

            dx, dy = directions[maze[start_x][start_y]]

            next_x, next_y = start_x + dx, start_y + dy

            return can_reach_exit(next_x, next_y, visited)

(4)普通位置路线

for dx, dy in directions.values():

            next_x, next_y = start_x + dx, start_y + dy

            if is_valid(next_x, next_y) and can_reach_exit(next_x, next_y, visited.copy()):

                return True

(5)判断循环因素:

陷入循环:在传送门中不断循环if (start_x, start_y) in visited

路线超出边界:0 <= x < N and 0 <= y < M

(6)判断位置安全

越界判断:if not is_valid(start_x, start_y)

循环检查:if (start_x, start_y) in visited

是否到达出口:if maze[start_x][start_y] == 'O'

(7)记录不能达到的位置数量

count = 0

for i in range(N):

    for j in range(M):

        if maze[i][j] != 'O':  

            if not can_reach_exit(i, j, set()):

                count += 1

  1. 思考:
  • 优化搜索算法: 在实际操作中,我意识到递归搜索可能会导致栈溢出,特别是在大型迷宫中。未来可以考虑使用迭代方法或优化递归深度,以提高算法的健壮性。
  • 处理复杂情况: 面对传送机关形成的复杂循环,我学会了如何使用数据结构来跟踪状态,这对于解决类似问题非常有帮助。
  • 代码重构: 在编写代码时,我注意到了一些可以重构的地方,比如将一些重复的代码段封装成函数,以提高代码的复用性和可维护性。
  • 测试用例: 在解题过程中,编写和测试多个用例是非常重要的。通过测试,我能够发现并修复代码中的错误,确保算法的正确性。