五月集训(第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;
}
};
东方欲晓,莫道君行早。