[LEETCODE]算法进阶自练习 11-12 DFS&BFS
11. DFS
简单
- 二叉树的最大深度 leetcode 104 递归解法(简单易理解):
int maxDepth(TreeNode* root) {
if(root == nullptr) return 0;
int leftDepth = maxDepth(root->left);
int rightDepth = maxDepth(root->right);
return max(leftDepth, rightDepth) + 1;
}
广度优先搜索(层序遍历):
int maxDepth(TreeNode* root) {
int ans = 0;
if(!root) return ans;
queue<TreeNode*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
while(size > 0){
TreeNode* node = queue.front(); queue.pop();
if(node->left) queue.push(node->left);
if(node->right) queue.push(node->right);
size--;
}
ans++;
}
return ans;
}
- 二叉树的最小深度 leetcode 111 递归解法:
int minDepth(TreeNode* root) {
if(!root) return 0;
if(root->left == nullptr && root->right == nullptr) return 1;
int minDep = INT_MAX;
if(root->left){
minDep = min(minDep,minDepth(root->left));
}
if(root->right){
minDep = min(minDep,minDepth(root->right));
}
return minDep + 1; // +1是加上当前节点
}
广度优先解法:
int minDepth(TreeNode* root) {
if(!root) return 0;
int ret = 0;
queue<pair<TreeNode*, int>> queue;
queue.emplace(root,1);
while (!queue.empty()) {
TreeNode *node = queue.front().first;
int depth = queue.front().second;
queue.pop();
if (node->left == nullptr && node->right == nullptr) {
return depth;
}
if (node->left != nullptr) {
queue.emplace(node->left, depth + 1);
}
if (node->right != nullptr) {
queue.emplace(node->right, depth + 1);
}
}
return 0;
}
中等
- 朋友圈 leetcode 547 DFS解法:
class Solution {
public:
void checkFriend(vector<vector<int>>& M, int i, vector<int>& visited){
visited[i] = 1;
int fsize = M.size();
for(int j=0; j<fsize; j++){
if(M[i][j] && !visited[j]){
checkFriend(M,j,visited);
}
}
}
int findCircleNum(vector<vector<int>>& M) {
int fsize = M.size();
vector<int> visited(fsize,0);
int count = 0;
for(int i=0; i<fsize; i++){
if(!visited[i]){
checkFriend(M,i, visited);
count++;
}
}
return count;
}
};
BFS解法:
int findCircleNum(vector<vector<int>>& M) {
int fsize = M.size();
vector<int> visited(fsize,0);
int count = 0;
queue<int> que;
for(int i=0; i<fsize; i++){
if(!visited[i]){
count++;
que.push(i);
while(!que.empty()){
int tmp = que.front();
que.pop();
visited[tmp] = 1;
for(int j=0; j<fsize; ++j){
if(M[tmp][j] && !visited[j]){
que.push(j);
}
}
}
}
}
return count;
}
并查集解法:
class Solution {
public:
int find(vector<int>& pv, int n){
if(pv[n] == -1) return n;
return find(pv, pv[n]);
}
void punion(vector<int>& pv, int m, int n){
int pm = find(pv,m);
int pn = find(pv,n);
if(pm != pn) pv[pm] = pn;
}
int findCircleNum(vector<vector<int>>& M) {
int fsize = M.size();
vector<int> pv(fsize,-1);
for(int i=0; i<fsize; ++i){
for(int j=0; j<fsize; ++j){
if(M[i][j] && i!=j) punion(pv,i,j);
}
}
int count = 0;
for(int i=0; i<fsize; ++i){
if(pv[i] == -1) count++;
}
return count;
}
};
- 找到最终的安全状态 leetcode 802 反向图解法:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
int gsize = graph.size();
vector<int> degree(gsize,0);
vector<vector<int>> rev(gsize,vector<int>(0));
for(int i=0; i<gsize; i++){
degree[i] = graph[i].size();
for(auto j:graph[i]){
rev[j].push_back(i);
}
}
vector<bool> safe(gsize,false);
queue<int> que;
for(int i=0; i<gsize; i++){
if(graph[i].size() == 0){
safe[i] = true;
que.push(i);
}
}
while(!que.empty()){
int t = que.front(); que.pop();
for(auto i:rev[t]){
degree[i]--;
if(degree[i] == 0){
que.push(i);
safe[i] = true;
}
}
}
vector<int> ret;
for(int i=0; i<gsize; i++){
if(safe[i]) ret.emplace_back(i);
}
return ret;
}
深度优先搜索解法:
bool checkSafe(vector<vector<int>>& graph, vector<int>& status, int node){
if(status[node] > 0) return status[node] == 2; // check visited
status[node] = 1; // visiting
for(int inner:graph[node]){
if(status[node] == 2) continue;
if(status[inner] == 1 || !checkSafe(graph,status,inner)) return false;
}
status[node] = 2;
return true;
}
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
int gsize = graph.size();
vector<int> status(gsize,0), ret; // status: 0 not visited, 1 visiting, 2 visited
for(int node=0; node<gsize; node++) if(checkSafe(graph, status, node)) ret.emplace_back(node);
return ret;
}
困难
-
矩阵中的最长递增路径 leetcode 329
-
扫雷游戏 leetcode 529 深度优先遍历解法:
class Solution {
vector<int> direction_x = {0, 1, 0, -1, 1, 1, -1, -1}; // x方向探测
vector<int> direction_y = {1, 0, -1, 0, 1, -1, 1, -1}; // y方向探测
public:
void checkMine(vector<vector<char>>& board, int x, int y){
int count = 0;
for(int i=0; i<8; ++i){
int tx = x + direction_x[i];
int ty = y + direction_y[i];
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size()){
continue;
}
count += (board[tx][ty] == 'M');
}
if(count > 0){
// 周边有地雷,对应第三种情况
board[x][y] = count + '0';
} else{
board[x][y] = 'B';
for(int i=0; i<8; ++i){
int tx = x + direction_x[i];
int ty = y + direction_y[i];
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size() || board[tx][ty] != 'E'){
continue;
}
checkMine(board, tx, ty);
}
}
}
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
int x = click[0], y = click[1];
if(board[x][y] == 'M'){
board[x][y] = 'X';
}
else{
checkMine(board, x, y);
}
return board;
}
};
广度优先遍历解法:
class Solution {
vector<int> direction_x = {0, 1, 0, -1, 1, 1, -1, -1}; // x方向探测
vector<int> direction_y = {1, 0, -1, 0, 1, -1, 1, -1}; // y方向探测
public:
void checkMine(vector<vector<char>>& board, int x, int y){
vector<vector<int>> visited(board.size(),vector<int>(board[0].size(),0));
visited[x][y] = 1;
queue<pair<int,int>> que;
que.push({x,y});
while(!que.empty()){
auto position = que.front();
que.pop();
int tmpX = position.first; int tmpY = position.second, count = 0;
for(int i=0; i<8; ++i){
int tx = direction_x[i] + tmpX;
int ty = direction_y[i] + tmpY;
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size()){
continue;
}
if(board[tx][ty] == 'M'){
count++;
}
}
if(count > 0){
board[tmpX][tmpY] = '0' + count;
}
else{
board[tmpX][tmpY] = 'B';
for(int i=0; i<8; ++i){
int tx = direction_x[i] + tmpX;
int ty = direction_y[i] + tmpY;
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size() || board[tx][ty] != 'E' || visited[tx][ty] == 1){
continue;
}
que.push({tx,ty});
visited[tx][ty] = 1;
}
}
}
}
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
int x = click[0], y = click[1];
if(board[x][y] == 'M'){
board[x][y] = 'X';
}
else{
checkMine(board, x, y);
}
return board;
}
};
- 单词接龙 leetcode 127 广度优先搜索:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
int wsize = beginWord.size();
map<string, vector<string>> graph;
int wlsize = wordList.size();
for(int i=0; i<wlsize; i++){
for(int j=0; j<wsize; j++){
// abc
string pattern_s = wordList[i].substr(0,j) + "*" + wordList[i].substr(j+1,wsize-j+2);
graph[pattern_s].push_back(wordList[i]);
}
}
queue<pair<string, int>> que;
que.push({beginWord,1});
map<string, int> visited;
visited[beginWord] = 1;
while(!que.empty()){
auto tmp = que.front();
que.pop();
string word = tmp.first;
int level = tmp.second;
for(int i=0; i<wsize; i++){
string pattern_s = word.substr(0,i) + "*" + word.substr(i+1,wsize-i+2);
//
vector<string>::iterator it = graph[pattern_s].begin();
while(it != graph[pattern_s].end()){
if(*it == endWord) return level+1;
if(!visited.count(*it)){
visited[*it] = 1;
que.push({*it,level+1});
}
it++;
}
}
}
return 0;
}
双向广度优先搜索:
class Solution {
private:
int wsize;
map<string, vector<string>> graph;
public:
Solution(){
wsize = 0;
}
int visitWordNode(queue<pair<string,int>>& que, map<string, int>& visitedBegin, map<string, int>& visitedEnd){
auto tmp = que.front(); que.pop();
string word = tmp.first; int level = tmp.second;
for(int i=0; i<wsize; i++){
string pattern_s = word.substr(0,i) + "*" + word.substr(i+1, wsize-i+2);
vector<string>::iterator it = graph[pattern_s].begin();
while(it != graph[pattern_s].end()){
if(visitedEnd.count(*it) != 0){
return level + visitedEnd[*it];
}
if(visitedBegin.count(*it) == 0){
visitedBegin[*it] = level+1;
que.push({*it, level+1});
}
it++;
}
}
return -1;
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
if(std::find(wordList.begin(), wordList.end(), endWord) == wordList.end()) return 0;
wsize = beginWord.size();
int wlsize = wordList.size();
for(int i=0; i<wlsize; i++){
for(int j=0; j<wsize; j++){
string pattern_s = wordList[i].substr(0,j) + "*" + wordList[i].substr(j+1,wsize-j+2);
graph[pattern_s].push_back(wordList[i]);
}
}
queue<pair<string, int>> queBegin, queEnd;
queBegin.push({beginWord,1});queEnd.push({endWord,1});
map<string, int> visitedBegin, visitedEnd;
visitedBegin[beginWord] = 1; visitedEnd[endWord] = 1; // 这里level记录了距离
while(!queBegin.empty() && !queEnd.empty()){
int ret = visitWordNode(queBegin, visitedBegin, visitedEnd);
if(ret > -1) return ret;
ret = visitWordNode(queEnd, visitedEnd, visitedBegin);
if(ret > -1) return ret;
}
return 0;
}
};
12.BFS
简单
- N叉树的层序遍历 leetcode 429 简单的BFS解法:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> ret;
if(root == nullptr) return ret;
queue<Node*> que;
que.push(root);
while(!que.empty()){
int size = que.size();
vector<int> t;
while(size > 0){
Node* node = que.front();
que.pop();
size--;
t.emplace_back(node->val);
for(auto& child:node->children){
que.push(child);
}
}
ret.emplace_back(t);
}
return ret;
}
- 二叉树的层序遍历 leetcode 102 同上还更简单了:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ret;
if(root == nullptr) return ret;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size = que.size();
vector<int> t;
while(size > 0){
TreeNode* node = que.front();
que.pop();
size--;
t.emplace_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
ret.emplace_back(t);
}
return ret;
}
- 二叉树的层序遍历II leetcode 107 加一个reverse就好了:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> ret;
if(root == nullptr) return ret;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size = que.size();
vector<int> t;
while(size > 0){
TreeNode* node = que.front();
que.pop();
size--;
t.emplace_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
ret.emplace_back(t);
}
reverse(ret.begin(),ret.end());
return ret;
}
中等
- 扫雷游戏 leetcode 529 深度优先遍历解法:
class Solution {
vector<int> direction_x = {0, 1, 0, -1, 1, 1, -1, -1}; // x方向探测
vector<int> direction_y = {1, 0, -1, 0, 1, -1, 1, -1}; // y方向探测
public:
void checkMine(vector<vector<char>>& board, int x, int y){
int count = 0;
for(int i=0; i<8; ++i){
int tx = x + direction_x[i];
int ty = y + direction_y[i];
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size()){
continue;
}
count += (board[tx][ty] == 'M');
}
if(count > 0){
// 周边有地雷,对应第三种情况
board[x][y] = count + '0';
} else{
board[x][y] = 'B';
for(int i=0; i<8; ++i){
int tx = x + direction_x[i];
int ty = y + direction_y[i];
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size() || board[tx][ty] != 'E'){
continue;
}
checkMine(board, tx, ty);
}
}
}
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
int x = click[0], y = click[1];
if(board[x][y] == 'M'){
board[x][y] = 'X';
}
else{
checkMine(board, x, y);
}
return board;
}
};
广度优先遍历解法:
class Solution {
vector<int> direction_x = {0, 1, 0, -1, 1, 1, -1, -1}; // x方向探测
vector<int> direction_y = {1, 0, -1, 0, 1, -1, 1, -1}; // y方向探测
public:
void checkMine(vector<vector<char>>& board, int x, int y){
vector<vector<int>> visited(board.size(),vector<int>(board[0].size(),0));
visited[x][y] = 1;
queue<pair<int,int>> que;
que.push({x,y});
while(!que.empty()){
auto position = que.front();
que.pop();
int tmpX = position.first; int tmpY = position.second, count = 0;
for(int i=0; i<8; ++i){
int tx = direction_x[i] + tmpX;
int ty = direction_y[i] + tmpY;
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size()){
continue;
}
if(board[tx][ty] == 'M'){
count++;
}
}
if(count > 0){
board[tmpX][tmpY] = '0' + count;
}
else{
board[tmpX][tmpY] = 'B';
for(int i=0; i<8; ++i){
int tx = direction_x[i] + tmpX;
int ty = direction_y[i] + tmpY;
if(tx < 0 || tx >= board.size() || ty < 0 || ty >= board[0].size() || board[tx][ty] != 'E' || visited[tx][ty] == 1){
continue;
}
que.push({tx,ty});
visited[tx][ty] = 1;
}
}
}
}
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
int x = click[0], y = click[1];
if(board[x][y] == 'M'){
board[x][y] = 'X';
}
else{
checkMine(board, x, y);
}
return board;
}
};
- 最小高度树 leetcode 310 BFS解法:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if(n==1) return {0};
if(n==2) return {0,1};
vector<int> indegree(n,0); // 每个顶点入度数量
vector<int> v;
vector<vector<int>> graph(n,v); // 图的数组 定点对应的邻接顶点
int esize = edges.size();
for(int i=0; i<esize; i++){
graph[edges[i][0]].push_back(edges[i][1]);
graph[edges[i][1]].push_back(edges[i][0]);
indegree[edges[i][0]]++;
indegree[edges[i][1]]++;
}
queue<int> que;
for(int i=0; i<n; i++){
if(indegree[i] == 1){
que.push(i);
}
}
int count = que.size();
while(n>2){
n -= count; // 将所有入度为1的节点删除
while(count--){
int tmp = que.front();
que.pop();
indegree[tmp] = 0; // 可以将入度设置为0了 que里面的都是入度为1的顶点
int vsize = graph[tmp].size();
// 处理邻接顶点
for(int i=0; i<vsize; i++){
if(indegree[graph[tmp][i]] != 0){
indegree[graph[tmp][i]]--;
if(indegree[graph[tmp][i]] == 1){
que.push(graph[tmp][i]);
}
}
}
}
count = que.size();
}
vector<int> ret;
while(!que.empty()){
ret.emplace_back(que.front());
que.pop();
}
return ret;
}