leetcode之迷宫问题---BFS 广度优先搜索

 前言:迷宫问题很常见,若求最小路径,一般用广度优先搜索,主要要注意几点:

1)对新加四个方向符合要求的位置到队列时,判断是否被访问过,INF代表未被访问 
d[nx][ny] == INF
2)到达终点的最小距离的表达式
d[nx][ny] = d[p.first][p.second] + 1;

3)存新的位置position(x,y)的定义,用pair不用map
typedef pair<int, int> position; 

4)新的四个方向的位置的定义
int dx[4] = {1, 0,-1, 0}; // 左右方向
int dy[4] = {0, 1, 0, -1};  // 上下方向
for (i = 0; i < 4; i++) { // 新的位置的定义
    int nx = p.first + dx[i];
    int ny = p.second + dy[i];
    ...
}
题目:
/*
 * 对于每个输入文件,第一行输入一个整数N(1<=N<=500),接下来N行,每行N个字符,表示这个迷宫的状态.
 * 其中’S’表示小华的位置,’E’表示终点,’#’表示障碍物,’.’表示可以走的地方.
 * Input:   3
            #S#
            ...
            E##
Output:     3
 思路:
1.从起点开始,先将其加入队列,设置距离为0;
2.从队列首端取出位置,将从这个位置能够到达的四个方向的位置加入队列,并且让这些位置的距离为上一个位置的距离加上1;
3.循环2直到将终点添加到队列中,这说明我们已经找到了路径;
 */
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

char INF = 0x3f3f3f3f; // 初始化时,队列存新的位置position(x,y)的值都为INF,对待放入队列的位置进行判断是否访问过
int d[3][3] = {0}; // 这里的值是可变的,由输入决定
typedef pair<int, int> position; // 存新的位置position(x,y)

void BFS(vector<vector<char>> &matrix, int x, int y, int Ex, int Ey) {
    if ((x < 0) || (y < 0) || (x >= matrix.size()) || (y >= matrix[0].size()) || matrix[x][y] == '#') {
        return;
    }
    queue<position> q;
    q.push(position(x, y));
    d[x][y] = 0; // 从起点出发将距离设为0,并放入队列首端
    int dx[4] = {1, 0,-1, 0}; // 左右方向
    int dy[4] = {0, 1, 0, -1};  // 上下方向
    int i;
    int index = 4;
    while (!q.empty()) {
        auto p  = q.front();
        q.pop();
        for (i = 0; i < 4; i++) {
            int nx = p.first + dx[i];
            int ny = p.second + dy[i];
            if (nx >= 0 && nx < matrix.size() && matrix[nx][ny] != '#' && d[nx][ny] == INF) { // 如果四个新的方向都没访问过
                q.push(position(nx, ny)); // 往队列中插入新的四个方向
                d[nx][ny] = d[p.first][p.second] + 1; // 距离加1
            }
            if (nx == Ex && ny == Ey) { // 如果到了终点,跳出循环,不再往队列中插入新的四个方向的位置
                break;
            }
        }
        if (i != index) { break; }
    }
}

int main()
{
    vector<vector<char>> matrix = {{'#', 'S', '#'},{'.', '.', '.'},{'E', '#', '#'}};
    int startX, startY, endX, endY;
    for (int i = 0; i < matrix.size(); i++) {
        for (int j = 0; j < matrix[0].size(); j++) {
            d[i][j] = INF;
            if (matrix[i][j] == 'S') {
                startX = i;
                startY = j;
            }
            if (matrix[i][j] == 'E') {
                endX = i;
                endY = j;
            }
        }
    }
    BFS(matrix, startX, startY, endX, endY); // 广度优先搜索
    cout << d[endX][endY] << endl; // 寻找到底终点的最短路径
    return 0;
}   
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
#include <queue>

using namespace std;

// 第一题:给定一个闭区间范围[m, n],1<=m<=n<=10^9,求[m,n]区间上位数为偶数的整数有多少个?
// 输入样例:m = 1, n = 100
// 输出样例:90
// 输出样例说明:[1,100]区间上,有10~99这些整数的位数是2位,是偶数,所以答案是10~99这些整数的数量,即90。
// 思路: 先判断m是哪个区间内,再判断n是哪个区间内,
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Solution {
public:
    
int mostDouble2(int m, int n) {
        vector<pair<int, int>> numbers;
        numbers.push_back(make_pair(10, 99));
        numbers.push_back(make_pair(100, 999));
        numbers.push_back(make_pair(1000, 9999));
        numbers.push_back(make_pair(100000, 999999));
        numbers.push_back(make_pair(10000000, 99999999));
        numbers.push_back(make_pair(1000000000, 1000000001));
        int finalNum = 0;
        cout << "---1-----" << endl;
        for (auto num:numbers) {
            int left = num.first;
            int right = num.second;
            cout << "---2-----" << left << right << endl;
            // 目标区间落在当前区间内
            if (m >= left && n <= right) {
                cout << "---3-----" << left << right << endl;
                return n - m + 1;
            }

            // 目标区间被当前区间bufen 包含
            if (m < left && n > right) {
                return right - left + 1;
            }
            // 计算右侧重叠区间长度(不满足第一个判断条件,则n一定大于rightNum)

            if (m >= left && m <= right) {
                return right - m + 1;
            }

            // 计算左侧重叠区间长度(不满足第一个判断条件,则m一定小于leftNum)
            if (n >= left && n <= right) {
                return n - left + 1;
            }
        }
    }
    // 一个机房里面有N个位置可以放N个服务器,每个服务器都有一个标签,标签为正整数1~N,且有可能有重复。
    // 输入一个标签列表(无序的),求最少移动多少个服务器可以让标签列表有序。
    // 输入样例:[1,1,2,3,5,4]
    // 输出样例:2
    // 输出样例说明:互换标签为5和4的服务器,即可使得标签列表有序
    
int minTrans(vector<int> &trans) {
        vector<int> sortedTrans(trans);
        int resultNum = 0;
        sort(sortedTrans.begin(), sortedTrans.end());
        for (int i = 0; i < trans.size(); i++) {
            if (trans[i] != sortedTrans[i]) {
                resultNum++;
            }
        }
        return resultNum;
    }
    // 第三题 某地突发一起重大交通事故,热心群众立即播打了120急救电话,事发时段正巧是下班高峰,路况不尽如人意。
    // 救护车司机打开地图matrix,matrix是给定的一个的矩阵,给定起点S(坐标 startX, startY)以及终点E(坐标 endX, endY)。
    // 地图上所有的0 都显示通畅路段,1 代表拥堵路段(拥堵路段不可通行)。为了能尽快将伤员送往医院,
    // 司机立即求助于市交通部指挥中心,指挥中心使用智慧交通提供的紧急救援功能,可以将地图上的一个拥堵路段(1)
    // 开辟出一道绿色通道变为通畅路段(0)。(注意:司机仅有一次开辟绿色通道的机会)司机一次只能往上、往下、往左、往右行驶一公里
    // ,请返回他从S开始并走到E所花的最短公里数。如果一定不能到达,请返回-1。
    //输入:matrix = [[0,0,1,0],[1,0,0,0]], startX = 0, startY = 0, endX = 0, endY = 3
    //输出:3
    //解释:司机在智慧交通提供的紧急救援功能的引导下可以将坐标为 (0, 2) 的拥堵路段开辟出一道绿色通道转变为通畅路段。
    // 这样的公里数最少,为 3。
    //输入:matrix = [[0,1,1,0],[1,0,0,0]], startX = 0, startY = 0, endX = 0, endY = 3
    //输出:5
    //解释:司机在智慧交通提供的紧急救援功能的引导下只能将坐标为(1, 0)的拥堵路段开辟出一条绿色通道变为通畅路段。
    // 这样的公里数为5。
    //输入:matrix = [[0,1,1,0],[1,1,0,0]], startX = 0, startY = 0, endX = 0, endY = 3
    //输出:-1
    //解释:司机被困在了起点。答案为-1。
    //限制:
    //matrix 大小不超过 100 * 100
    //0 <= 拥堵路段(1)的个数 <= 50
    //起始点和终点都不是拥堵路段。
    // DFS解法 : 使用一个bool变量hasGreenPathUsed来记录是否已使用清除路障,使用一个二维数组visited来记录是否访问过,
    // 使用一个int变量curMinStepNumber来存储当前的最短路径,然后利用常用的回溯法去遍历每一条可能到达的路径,并记录其路径长度,
    // 与当前的最小路径长度做比较通过剪枝:当前路径长度已超过当前最小路径长度,即后续的路径探索也不会得到一个更短的路径。

    
vector<pair<int, int>> nextPos;
    int curMinStepNumber = 49999;
    int finalPosX;
    int finalPosY;
    vector<vector<int>> visited;

    void getnextPos() {
        nextPos.push_back(make_pair(0, 1));
        nextPos.push_back(make_pair(1, 0));
        nextPos.push_back(make_pair(-1, 0));
        nextPos.push_back(make_pair(0, -1));
    }

    void findThePath(vector<vector<int>> &matrix, int startX, int startY, int curStepNumber, bool hasGreenPathUsed) {
        if (startX == finalPosX && startY == finalPosY) {
            curMinStepNumber = curStepNumber < curMinStepNumber ? curStepNumber : curMinStepNumber;
        } else {
            // 进行剪枝
            if (curStepNumber < curMinStepNumber) {
                for (auto next : nextPos) {
                    int nextX = startX + next.first;
                    int nextY = startY + next.second;
                    if (nextX >= 0 && nextX < matrix.size() && nextY >= 0 && nextY < matrix[0].size() &&
                        !visited[nextX][nextY]) {
                        visited[nextX][nextY] = 1;
                        if (matrix[nextX][nextY] == 1) {
                            if (!hasGreenPathUsed) {
                                findThePath(matrix, nextX, nextY, curStepNumber + 1, true);// 清除当前路障
                            }
                        } else {
                            findThePath(matrix, nextX, nextY, curStepNumber + 1, hasGreenPathUsed);
                        }
                        visited[nextX][nextY] = 0;// 回溯
                    }
                }
            }
        }
    }
    int rescue(vector<vector<int>> &matrix, int startX, int startY, int endX, int endY) {
        for (int i = 0; i < matrix.size(); i++) {
            vector<int> tempVec(matrix[0].size(), 0);
            visited.push_back(tempVec);
        }
        getnextPos();
        finalPosX = endX;
        finalPosY = endY;
        visited[startX][startY] = 1;
        findThePath(matrix, startX, startY, 0, false);
        return curMinStepNumber < 49999 ? curMinStepNumber : -1;
    }


    // BFS 解法: 用一个队列来存3元组
    vector<pair<int, int>> getNextVec() {
        vector<pair<int, int>> nextPos;
        nextPos.push_back(make_pair(0, 1));
        nextPos.push_back(make_pair(1, 0));
        nextPos.push_back(make_pair(-1, 0));
        nextPos.push_back(make_pair(0, -1));
        return nextPos;
    }

    int rescue1(vector<vector<int>> &matrix, int startX, int startY, int endX, int endY) {

        vector<pair<int, int>> nextPos = getNextVec();
        vector<vector<int>> visitedWithShield(matrix.size(), vector<int>(matrix[0].size(), 0));
        vector<vector<int>> visitedNoShield(matrix.size(), vector<int>(matrix[0].size(), 0));

        queue<tuple<int, int, int>> paths; // 需要保存3个及以上的数据时就需要使用tuple元组
        paths.push(make_tuple(startX, startY, 0));
        int shortestPath = 0;
        while (!paths.empty()) {
            shortestPath++;
            int size = paths.size();
            while (size-- > 0) {
                int curX = get<0>(paths.front());
                int curY = get<1>(paths.front());
                int isShiledUsed = get<2>(paths.front());
                paths.pop();
                if (curX == endX && curY == endY) {
                    return shortestPath - 1;
                }
                for (auto next : nextPos) {
                    int nextX = curX + next.first;
                    int nextY = curY + next.second;
                    if (nextX >= 0 && nextX < matrix.size() && nextY >= 0 && nextY < matrix[0].size()) {
                        if (matrix[nextX][nextY] == 1) {
                            // 下一个位置有路障,同时清除路障还没用过,且下个位置不是清障走过的位置
                            if (isShiledUsed == 0 && !visitedWithShield[nextX][nextY]) {
                                paths.push(make_tuple(nextX, nextY, 1));
                                visitedWithShield[nextX][nextY] = 1;
                            }
                        } else {
                            // 下个位置不是路障,没用过路障清除或者用过路障清除都是可以继续走下去的
                            if ((isShiledUsed == 0 && !visitedNoShield[nextX][nextY]) ||
                                (isShiledUsed == 1 && !visitedWithShield[nextX][nextY])) {
                                paths.push(make_tuple(nextX, nextY, isShiledUsed));
                                if (isShiledUsed == 0) {
                                    visitedNoShield[nextX][nextY] = 1;
                                } else {
                                    visitedWithShield[nextX][nextY] = 1;
                                }
                            }
                        }
                    }
                }
            }
        }
        return -1;
    }


    /* 19. 水域大小 你有一个用于表示一片土地的整数矩阵land,该矩阵中每个点的值代表对应地点的海拔高度。若值为0则表示水域。
     * 由垂直、水平或对角连接的水域为池塘。池塘的大小是指相连接的水域的个数。编写一个方法来计算矩阵中所有池塘的大小,返回值需要从小到大排序。
    输入:
    [
      [0,2,1,0],
      [0,1,0,1],
      [1,1,0,1],
      [0,1,0,1]
    ]
    输出: [1,2,4]
    提示:
    0 < len(land) <= 1000
    0 < len(land[i]) <= 1000
    思路:利用深度搜索,每次遇到land[i][j]为0,进行一次DFS,count 加1,
     方向数组为dx[8] = {0, 1, 1, 1, 0, -1, -1, -1}, dy[8] = {1, 1, 0, -1, -1, -1, 0, 1},
     利用land[x][y] = -1来染色,表示已经访问过
    * */

    
vector<int> pondSizes(vector<vector<int>> &land) {
        vector<int> result;
        for (int i = 0; i < land.size(); ++i) {
            for (int j = 0; j < land[i].size(); ++j) {
                if (land[i][j] == 0) {
                    int count = 0;
                    dfs(i, j, count, land); // 有效的一次dfs
                    if (count != 0) {  // 计算鱼塘大小
                        result.push_back(count);
                    }
                }
            }
        }
        sort(result.begin(), result.end());
        return result;
    }

    void dfs(int x, int y, int &count, vector<vector<int>> &land) {
        land[x][y] = -1; // 染色
        count++;
        int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1}, dy[8] = {1, 1, 0, -1, -1, -1, 0, 1}; //方向数组
        for (int i = 0; i < 8; ++i) {
            int newX = x + dx[i];
            int newY = y + dy[i];
            if (newX >= 0 && newX < land.size() && newY >= 0 && newY < land[0].size() && land[newX][newY] == 0) {
                dfs(newX, newY, count, land);
            }
        }
    }
    /* 04. 检查二叉树平衡性
     * 实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。
     * 给定二叉树 [3,9,20,null,null,15,7]
        3
       / \
      9  20
        /  \
       15   7
    返回 true 。
     给定二叉树 [1,2,2,3,3,null,null,4,4]
      1
     / \
    2   2
    / \
    3   3
    / \
    4   4
    返回 false 。
     * */
 
   bool flag = true;

    bool isBalanced(TreeNode *root) {
        dfs(root);
        return flag;
    }

    int dfs(TreeNode *root) {
        if (!root) return 0;
        int left = dfs(root->left);
        int right = dfs(root->right);
        if (abs(left - right) > 1) {
            flag = false;
        }
        return max(left, right) + 1;
    }
    /* 695. 岛屿的最大面积 给定一个包含了一些 0 和 1 的非空二维数组 grid 。
    一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。
    你可以假设 grid 的四个边缘都被 0(代表水)包围着。
    找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)
     示例 1:
    [[0,0,1,0,0,0,0,1,0,0,0,0,0],
     [0,0,0,0,0,0,0,1,1,1,0,0,0],
     [0,1,1,0,1,0,0,0,0,0,0,0,0],
     [0,1,0,0,1,1,0,0,1,0,1,0,0],
     [0,1,0,0,1,1,0,0,1,1,1,0,0],
     [0,0,0,0,0,0,0,0,0,0,1,0,0],
     [0,0,0,0,0,0,0,1,1,1,0,0,0],
     [0,0,0,0,0,0,0,1,1,0,0,0,0]]
    对于上面这个给定矩阵应返回 6。注意答案不应该是 11 ,因为岛屿只能包含水平或垂直的四个方向的 1 。
     示例 2:
    [[0,0,0,0,0,0,0,0]]
    对于上面这个给定的矩阵, 返回 0。
     注意: 给定的矩阵grid 的长度和宽度都不超过 50。
     思路:
    1)先排除全为0的情况,返回最大岛屿面积0
    2)从岛屿的grid[i][j]=1开始,依次对当前坐标的垂直和水平四个方向进行深度搜索,每次DFS遇到land[newX][newY] == 1,面积count加1,
    然后把每条路径的结果存于vector中,按照从大到小对vector排序,取vector第一个值为返回结果。
    3)采用land[x][y] = -1进行染色,表示已经访问过。
    * */
    
int maxAreaOfIsland(vector<vector<int>> &grid) {
        vector<int> vec;
        int cnt = 0;
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[0].size(); ++j) {
                if (grid[i][j] == 0) {
                    cnt++;
                }
            }
        }
        if (cnt == (grid.size() * grid[0].size())) {
            return 0;
        }
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[i].size(); ++j) {
                int count = 0;
                if (grid[i][j] == 1) {
                    DFS(i, j, count, grid); // 有效的一次dfs
                    if (count != 0) {  // 计算大小
                        vec.push_back(count);
                    }
                }
            }
        }
        sort(vec.begin(), vec.end(), greater<int>());
        return vec[0];
    }

    void DFS(int x, int y, int &count, vector<vector<int>> &land) {
        land[x][y] = -1; // 染色
        count++;
        int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}; //方向数组
        for (int i = 0; i < 4; ++i) {
            int newX = x + dx[i];
            int newY = y + dy[i];
            if (newX >= 0 && newX < land.size() && newY >= 0 && newY < land[0].size() && land[newX][newY] == 1) {
                DFS(newX, newY, count, land);
            }
        }
    }
    /* 1254. 统计封闭岛屿的数目   有一个二维矩阵 grid ,每个位置要么是陆地(记号为 0 )要么是水域(记号为 1 )。
    我们从一块陆地出发,每次可以往上下左右 4 个方向相邻区域走,能走到的所有陆地区域,我们将其称为一座「岛屿」。
    如果一座岛屿 完全 由水域包围,即陆地边缘上下左右所有相邻区域都是水域,那么我们将其称为 「封闭岛屿」。
    请返回封闭岛屿的数目。即被 1 区域包围
     * */
    
int closedIsland(vector<vector<int>> &grid) {
        int count = 0;
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[0].size(); ++j) {
                if (grid[i][j] == 0) {
                    if (DFS(i, j, grid)) {
                        count++;
                    }
                }
            }
        }
        return count;
    }

    bool DFS(int x, int y, vector<vector<int>> &land) {
        if (x < 0 || x >= land.size() || y < 0 || y >= land[0].size()) {
            return false; //是否到达边界,一次dfs搜索中只要有一个地方最终走到这儿就不是封闭岛屿了
        }
        if (land[x][y] != 0) { //如果是海洋或是已经访问过的陆地则返回false,因为这两种情况不需要继续遍历,且也没找到边界
            return true;
        }
        land[x][y] = -1; // 染色
        bool up = DFS(x - 1, y, land);
        bool down = DFS(x + 1, y, land);
        bool left = DFS(x, y - 1, land);
        bool right = DFS(x, y + 1, land);
        if (up && down && left && right) {
            return true;
        }
        return false;
    }
};

main函数

int main() {
    Solution solution;
    cout << "---------test1-------------" << endl;
    int m = 1, n = 100;
    cout << solution.mostDouble2(m, n) << endl;
    cout << "---------test2-------------" << endl;
    vector<int> trans = {1, 1, 2, 3, 5, 4};
    cout << solution.minTrans(trans) << endl;
    cout << "---------test3-------------" << endl;
    vector<vector<int>> matrix = {{0, 0, 1, 0},
                                  {1, 0, 0, 0}};
    int startX = 0, startY = 0, endX = 0, endY = 3;
    cout << solution.rescue(matrix, startX, startY, endX, endY) << endl; // 3

    cout << "---------test 19. 水域大小 -------------" << endl;
    vector<vector<int>> land = {{0, 2, 1, 0},
                                {0, 1, 0, 1},
                                {1, 1, 0, 1},
                                {0, 1, 0, 1}};
    vector<int> poolSize = solution.pondSizes(land);
    cout << poolSize[0] << poolSize[1] << poolSize[2] << endl; // {1,2,4}
    cout << "---------test 04.检查二叉树平衡性 -------------" << endl;
    // 初始化一棵树
    TreeNode *root = new TreeNode(3);
    TreeNode *b1 = new TreeNode(9);
    TreeNode *b2 = new TreeNode(20);
    TreeNode *c3 = new TreeNode(15);
    TreeNode *c4 = new TreeNode(7);

    root->left = b1;
    root->right = b2;

    b2->left = c3;
    b2->right = c4;
    vector<int> ret;
    cout << solution.isBalanced(root) << endl; // {1,2,4}

    cout << "---------test 695. 岛屿的最大面积  -------------" << endl;
    vector<vector<int>> grid1 = {{0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                                 {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0},
                                 {0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
                                 {0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0},
                                 {0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0},
                                 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
                                 {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0},
                                 {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0}};
    vector<vector<int>> grid = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
    int maxArea = solution.maxAreaOfIsland(grid1);
    cout << "maxArea: " << maxArea << endl; // {1,2,4}

    cout << "---------test 1254. 统计封闭岛屿的数目   -------------" << endl;
    vector<vector<int>> gridLand = {{0, 0, 1, 0, 0},
                                    {0, 1, 0, 1, 0},
                                    {0, 1, 1, 1, 0}};
    int closedIslandNum = solution.closedIsland(gridLand);
    cout << "closedIslandNum: " << closedIslandNum << endl; // 2
}

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值