[LEETCODE]算法进阶自练习 11-12 DFS&BFS

223 阅读5分钟

[LEETCODE]算法进阶自练习 11-12 DFS&BFS

11. DFS

简单
  1. 二叉树的最大深度 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;
    }
  1. 二叉树的最小深度 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;
    }
中等
  1. 朋友圈 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;
    }
};
  1. 找到最终的安全状态 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;
    }
困难
  1. 矩阵中的最长递增路径 leetcode 329

  2. 扫雷游戏 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;
    }
};
  1. 单词接龙 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

简单
  1. 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;
    }
  1. 二叉树的层序遍历 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;
    }
  1. 二叉树的层序遍历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; 
    }
中等
  1. 扫雷游戏 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;
    }
};
  1. 最小高度树 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;
    }