牛客题解 | 走迷宫

题目

题目链接

解题思路

BFS求最短路径解题思路

1. 问题分析

  • 二维网格中找最短路径
  • 可以上下左右四个方向移动
  • 有障碍物不能通过
  • 需要判断是否能到达目标点

2. 解题步骤

  1. 数据结构

    - 使用二维数组存储网格
    - 使用队列进行BFS
    - 使用二维数组记录距离
    - 定义四个方向的移动:dx[] = {-1,1,0,0}, dy[] = {0,0,-1,1}
    
  2. BFS实现

    - 从起点开始BFS
    - 每次取出队首位置,尝试四个方向
    - 对每个可以移动到的新位置:
      * 检查是否越界
      * 检查是否是障碍物
      * 检查是否已访问
      * 更新距离并加入队列
    
  3. 判断结果

    - 如果到达终点,返回距离
    - 如果队列空了还没到达,返回-1
    

3. 注意事项

  1. 坐标转换:

    • 输入是从1开始的坐标
    • 数组索引从0开始
    • 需要进行转换
  2. 边界检查:

    • 检查是否越界
    • 检查是否是障碍物
    • 检查是否已访问
  3. 优化:

    • 可以用visited数组代替dist数组
    • 可以在找到终点时立即返回

代码

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

struct Point {
    int x, y, step;
    Point(int _x, int _y, int _s) : x(_x), y(_y), step(_s) {}
};

class Solution {
public:
    int dx[4] = {-1, 1, 0, 0};
    int dy[4] = {0, 0, -1, 1};
    
    int shortestPath(vector<string>& grid, int xs, int ys, int xt, int yt) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<bool>> visited(n, vector<bool>(m, false));
        
        queue<Point> q;
        q.push(Point(xs-1, ys-1, 0));  // 坐标转换
        visited[xs-1][ys-1] = true;
        
        while (!q.empty()) {
            Point cur = q.front();
            q.pop();
            
            // 到达终点
            if (cur.x == xt-1 && cur.y == yt-1) {
                return cur.step;
            }
            
            // 尝试四个方向
            for (int i = 0; i < 4; i++) {
                int nx = cur.x + dx[i];
                int ny = cur.y + dy[i];
                
                // 检查新位置是否有效
                if (nx >= 0 && nx < n && ny >= 0 && ny < m 
                    && !visited[nx][ny] && grid[nx][ny] == '.') {
                    visited[nx][ny] = true;
                    q.push(Point(nx, ny, cur.step + 1));
                }
            }
        }
        
        return -1;  // 无法到达
    }
};

int main() {
    int n, m;
    cin >> n >> m;
    
    int xs, ys, xt, yt;
    cin >> xs >> ys >> xt >> yt;
    
    vector<string> grid(n);
    for (int i = 0; i < n; i++) {
        cin >> grid[i];
    }
    
    Solution sol;
    cout << sol.shortestPath(grid, xs, ys, xt, yt) << endl;
    
    return 0;
}
import java.util.*;

public class Main {
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};
    
    static class Point {
        int x, y, step;
        Point(int x, int y, int step) {
            this.x = x;
            this.y = y;
            this.step = step;
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        
        int xs = sc.nextInt() - 1;  // 坐标转换
        int ys = sc.nextInt() - 1;
        int xt = sc.nextInt() - 1;
        int yt = sc.nextInt() - 1;
        
        char[][] grid = new char[n][m];
        for (int i = 0; i < n; i++) {
            grid[i] = sc.next().toCharArray();
        }
        
        // BFS
        boolean[][] visited = new boolean[n][m];
        Queue<Point> q = new LinkedList<>();
        q.offer(new Point(xs, ys, 0));
        visited[xs][ys] = true;
        
        int result = -1;
        while (!q.isEmpty()) {
            Point cur = q.poll();
            
            if (cur.x == xt && cur.y == yt) {
                result = cur.step;
                break;
            }
            
            for (int i = 0; i < 4; i++) {
                int nx = cur.x + dx[i];
                int ny = cur.y + dy[i];
                
                if (nx >= 0 && nx < n && ny >= 0 && ny < m 
                    && !visited[nx][ny] && grid[nx][ny] == '.') {
                    visited[nx][ny] = true;
                    q.offer(new Point(nx, ny, cur.step + 1));
                }
            }
        }
        
        System.out.println(result);
    }
}
from collections import deque

def shortest_path(grid, xs, ys, xt, yt):
    n, m = len(grid), len(grid[0])
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]
    
    # 坐标转换
    xs, ys = xs-1, ys-1
    xt, yt = xt-1, yt-1
    
    # BFS
    visited = [[False] * m for _ in range(n)]
    q = deque([(xs, ys, 0)])  # (x, y, steps)
    visited[xs][ys] = True
    
    while q:
        x, y, steps = q.popleft()
        
        if x == xt and y == yt:
            return steps
            
        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            if (0 <= nx < n and 0 <= ny < m 
                and not visited[nx][ny] and grid[nx][ny] == '.'):
                visited[nx][ny] = True
                q.append((nx, ny, steps + 1))
                
    return -1

# 读入数据
n, m = map(int, input().split())
xs, ys, xt, yt = map(int, input().split())
grid = [input() for _ in range(n)]

# 输出结果
print(shortest_path(grid, xs, ys, xt, yt))

算法及复杂度分析

  • 算法:BFS求最短路径
  • 时间复杂度: O ( N × M ) \mathcal{O}{(N×M)} O(N×M)
    • 每个格子最多访问一次
  • 空间复杂度: O ( N × M ) \mathcal{O}{(N×M)} O(N×M)
    • 需要距离数组和队列
练习赛142是一场编程竞赛,通常包含多个算法题目,涵盖如数组、字符串、链表、动态规划等常见数据结构与算法知识点。针对这类比赛的解题思路和方法,可以从以下几个方面进行分析: ### 题目类型与解题策略 1. **数组相关问题** - 常见的题目包括查找数组中出现次数超过一半的数字、寻找缺失的数字、求解最大子数组和等。 - 解题方法包括使用哈希表统计频率、摩尔投票法(适用于多数元素问题)、双指针技巧或前缀和优化。 2. **链表操作** - 链表题目可能涉及反转链表、判断链表是否有环、找出两个链表的相交节点等。 - 例如,在找两个链表相交点的问题中,可以先计算各自长度,然后让长链表先差值步数,再同步遍历比较节点地址[^3]。 3. **字符串处理** - 包括最长回文子串、无重复字符的最长子串等。 - 可采用滑动窗口、动态规划或中心扩展法等策略。 4. **树与图** - 树相关的题目可能涉及二叉树的遍历、路径和、最近公共祖先等问题。 - 图论问题可能需要使用深度优先搜索(DFS)、广度优先搜索(BFS)或拓扑排序等算法。 5. **动态规划** - 动态规划常用于解决背包问题、最长递增子序列、编辑距离等。 - 关键在于定义状态转移方程,并通过迭代或记忆化搜索进行求解。 6. **贪心算法** - 适用于区间调度、活动选择、硬币找零等问题。 - 贪心策略的核心在于每一步都做出局部最优选择。 ### 示例代码:摩尔投票法解决“多数元素”问题 ```python def majorityElement(nums): count = 0 candidate = None for num in nums: if count == 0: candidate = num count += (1 if num == candidate else -1) return candidate ``` 该算法时间复杂度为 O(n),空间复杂度为 O(1),非常适合处理大规模输入的数据集[^2]。 ### 提升解题能力的建议 - **刷题积累经验**:在 LeetCode、Codeforces、AtCoder 等平台上持续练习,熟悉各种题型。 - **学习经典算法**:掌握常见的算法模板,如二分查找、归并排序、快速选择等。 - **阅读官方题解与讨论区**:了解不同解法的优劣,尤其是最优解的时间复杂度分析。 - **模拟比赛训练**:定期参加在线编程比赛,提升实战能力和代码调试速度。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值