五月集训(第17天)—广度优先搜索(BFS)

广度优先搜索(Breadth-First Search, BFS)

1. LCP 44. 开幕式焰火

    思路:
        BFS整棵二叉树,记录每种颜色出现的次数。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int numColor(TreeNode* root) {
        int cnt = 0;
        int hash[1001];
        queue<TreeNode*> q;
        q.push(root);
        memset(hash, 0, sizeof(hash));
        while (!q.empty()) {
            TreeNode *now = q.front();
            q.pop();
            if (now) {
                if (!hash[now->val]) {
                    hash[now->val] = 1;
                    cnt++;
                }
                q.push(now->left);
                q.push(now->right);
            }
        }
        return cnt;
    }
};

2. 102. 二叉树的层序遍历

    思路:
        BFS二叉树,记录每个节点的深度,根据深度将每个节点的值放入对应的集合中,的到层序遍历的结果。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (root == NULL) return {};

        vector<vector<int>> ret;
        unordered_map<TreeNode *, int> dep;
        queue<TreeNode *> q;
        q.push(root);
        dep[root] = 0;
        int dep_pre = -1;

        while (!q.empty()) {
            TreeNode *now = q.front();
            q.pop();

            if (dep_pre != dep[now]) {
                dep_pre = dep[now];
                ret.push_back({now->val});
            } else {
                ret[dep_pre].push_back(now->val);
            }
            
            if (now->left) {
                q.push(now->left);
                dep[now->left] = dep[now] + 1;
            }
            if (now->right) {
                q.push(now->right);
                dep[now->right] = dep[now] + 1;
            }
        }
        return ret;
    }
};

3. 1609. 奇偶树

    思路:
        利用第二题层序遍历的结果进行判断,满足条件的即为奇偶树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (root == NULL) return {};

        vector<vector<int>> ret;
        unordered_map<TreeNode *, int> dep;
        queue<TreeNode *> q;
        q.push(root);
        dep[root] = 0;
        int dep_pre = -1;

        while (!q.empty()) {
            TreeNode *now = q.front();
            q.pop();

            if (dep_pre != dep[now]) {
                dep_pre = dep[now];
                ret.push_back({now->val});
            } else {
                ret[dep_pre].push_back(now->val);
            }
            
            if (now->left) {
                q.push(now->left);
                dep[now->left] = dep[now] + 1;
            }
            if (now->right) {
                q.push(now->right);
                dep[now->right] = dep[now] + 1;
            }
        }
        return ret;
    }

    bool isEvenOddTree(TreeNode* root) {
        vector<vector<int>> Tree_order;
        Tree_order = levelOrder(root);

        int level_num = Tree_order.size();
        int set_num;

        for (int i = 0; i < level_num; i++) {
            if (i&1) {
                set_num = Tree_order[i].size();
                if (Tree_order[i][0]&1) return false;
                for (int j = 1; j < set_num; j++) {
                    if (!(Tree_order[i][j]&1) && (Tree_order[i][j] < Tree_order[i][j-1]))
                        continue;
                    else return false;
                }
            } else {
                set_num = Tree_order[i].size();
                if (!(Tree_order[i][0]&1)) return false;
                for (int j = 1; j < set_num; j++) {
                    if ((Tree_order[i][j]&1) && (Tree_order[i][j] > Tree_order[i][j-1]))
                        continue;
                    else return false;
                }
            }
        }
        return true;
    }
};

4. 1263. 推箱子

    思路:
        把箱子和人的位置信息打包作为一个状态,记录每个状态下最小的推箱子步数,不断更新答案。
        每次让人沿着地图走动(BFS),如果面前有箱子,且走到了箱子处,则代表推动箱子走了一格,否则箱子没动(但也是一种新的状态,可能有其他状态由该状态转移而得,所以也需要更新)。

class Solution {
    int n, m;
    
    int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右 下 左 上
public:
    int pack(int sx, int sy, int bx, int by) {
        return (sx << 15) | (sy << 10) | (bx << 5) | by;
    }

    bool is_valid(int x, int y, vector<vector<char>>& grid) {
        if (x < 0 || x >= n || y < 0 || y >= m) return false;
        if (grid[x][y] == '#') return false;
        return true;
    }

    int minPushBox(vector<vector<char>>& grid) {
        int sx = -1, sy = -1, bx = -1, by = -1;
        int ans = -1;
        queue<int> q;
        int step[1 << 20];

        n = grid.size();
        m = grid[0].size();
        // 获取人和箱子的起始坐标
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 'S') {
                    sx = i;
                    sy = j;
                    grid[i][j] = '.';
                }
                if (grid[i][j] == 'B') {
                    bx = i;
                    by = j;
                    grid[i][j] = '.';
                }
                if (sx != -1 && bx != -1) break;
            }
            if (sx != -1 && bx != -1) break;
        }

        // 状态压缩,地图的尺寸范围【1,20】,可以用5位二进制数表示
        // 利用一个整数代替了四位数组,节省空间
        int s = pack(sx, sy, bx, by);

        // BFS
        memset(step, -1, sizeof(step));
        q.push(s);
        step[s] = 0;
        while (!q.empty()) {
            s = q.front();
            q.pop();

            sx = (s >> 15) & 31;
            sy = (s >> 10) & 31;
            bx = (s >> 5) & 31;
            by = s & 31;

            if (grid[bx][by] == 'T') {
                if (ans == -1 || ans > step[s]) {
                    ans = step[s];
                }
            }

            int sx_next, sy_next, bx_next, by_next;
            for (int i = 0; i < 4; i++) {
                sx_next = sx + dir[i][0];
                sy_next = sy + dir[i][1];

                if (!is_valid(sx_next, sy_next, grid)) continue;

                if (sx_next == bx && sy_next == by) {   /* 人面前有箱子且人走到了箱子位置,即代表推动箱子同方向前进一格 */
                    bx_next = bx + dir[i][0];
                    by_next = by + dir[i][1];

                    if (!is_valid(bx_next, by_next, grid)) continue;

                    int temp_s = pack(sx_next, sy_next, bx_next, by_next);
                    if (step[s] + 1 < step[temp_s] || step[temp_s] == -1) { /* 如果箱子当前路径比之前到达的要短,或者第一次到达,则更新最短的推动次数 */
                        step[temp_s] = step[s] + 1;
                        q.push(temp_s);
                    }
                } else {    /* 人的面前没有箱子 */
                    int temp_s = pack(sx_next, sy_next, bx, by);
                    if (step[s] < step[temp_s] || step[temp_s] == -1) {
                        step[temp_s] = step[s];
                        q.push(temp_s);
                    }  
                }
            }
        }
        return ans;

    }
};
posted @ 2022-05-17 08:04  番茄元  阅读(31)  评论(0)    收藏  举报