【数据结构c++】搜索(十三)

6.1 广度优先搜索(BFS)

在这里插入图片描述
在这里插入图片描述

  • 二进制矩阵中的最短路径: https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/
    在这里插入图片描述
    在这里插入图片描述

    // 求最短路径通常使用广度优先搜索,可以用队列实现。
    // 从下标 [0,0] 开始遍历,每次寻找该点的八个方向是否可走,若可走就入队,继续执行该操作,最后走到 [n-1,n-1] 时,
    // 此时执行最外层循环的次数便是最短路径长度。(类似二叉树的层序遍历)
    
    class Solution {
    public:
        int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
            if(grid[0][0]==1)return -1;
            int n=grid.size(),ans=1;
            const int dire[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,-1},{-1,1}};
            queue<pair<int,int> > q;
            q.emplace(0,0);         //从0,0开始
            grid[0][0]=1;           //标记为1代表走过
            while(!q.empty()){      //bfs
                int m=q.size();
                while(m--){
                    auto [x,y]=q.front();
                    q.pop();
                    if(x==n-1&&y==n-1)return ans;
                    for(int i=0;i<8;i++){                       //遍历八个方向的
                        int nx=x+dire[i][0];
                        int ny=y+dire[i][1];
                        if(nx<0||ny<0||nx>=n||ny>=n)continue;   //判断是否越界
                        if(grid[nx][ny]==0){        //判断是否能走
                            q.emplace(nx,ny);
                            grid[nx][ny]=1;         //标记
                        }
                    }
                }
                ans++;          //记录循环次数
            }
            return -1;
        }
    };
    
  • 单词接龙: https://leetcode-cn.com/problems/word-ladder/
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    class Solution {
    public:
        unordered_map<string, int> wordId;
        vector<vector<int>> edge;
        int nodeNum = 0;
    
        void addWord(string& word) {
            if (!wordId.count(word)) {
                wordId[word] = nodeNum++;
                edge.emplace_back();
            }
        }
    
        void addEdge(string& word) {
            addWord(word);
            int id1 = wordId[word];
            for (char& it : word) {
                char tmp = it;
                it = '*';
                addWord(word);
                int id2 = wordId[word];
                edge[id1].push_back(id2);
                edge[id2].push_back(id1);
                it = tmp;
            }
        }
    
        int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
            for (string& word : wordList) {
                addEdge(word);
            }
            addEdge(beginWord);
            if (!wordId.count(endWord)) {
                return 0;
            }
            vector<int> dis(nodeNum, INT_MAX);
            int beginId = wordId[beginWord], endId = wordId[endWord];
            dis[beginId] = 0;
    
            queue<int> que;
            que.push(beginId);
            while (!que.empty()) {
                int x = que.front();
                que.pop();
                if (x == endId) {
                    return dis[endId] / 2 + 1;
                }
                for (int& it : edge[x]) {
                    if (dis[it] == INT_MAX) {
                        dis[it] = dis[x] + 1;
                        que.push(it);
                    }
                }
            }
            return 0;
        }
    };
    

    在这里插入图片描述

6.2 深度优先搜索(DFS)

在这里插入图片描述

  • 岛屿的最大面积: https://leetcode-cn.com/problems/max-area-of-island/
    在这里插入图片描述
    在这里插入图片描述

    class Solution {
        int dfs(vector<vector<int>>& grid, int cur_i, int cur_j) {
            if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i]					[cur_j] != 1) {
                return 0;
            }
            grid[cur_i][cur_j] = 0;
            int di[4] = {0, 0, 1, -1};
            int dj[4] = {1, -1, 0, 0};
            int ans = 1;
            for (int index = 0; index != 4; ++index) {
                int next_i = cur_i + di[index], next_j = cur_j + dj[index];
                ans += dfs(grid, next_i, next_j);
            }
            return ans;
        }
    public:
        int maxAreaOfIsland(vector<vector<int>>& grid) {
            int ans = 0;
            for (int i = 0; i != grid.size(); ++i) {
                for (int j = 0; j != grid[0].size(); ++j) {
                    ans = max(ans, dfs(grid, i, j));
                }
            }
            return ans;
        }
    };
    

    在这里插入图片描述

  • 岛屿数量: https://leetcode-cn.com/problems/number-of-islands/
    在这里插入图片描述
    在这里插入图片描述

    class Solution {
    private:
        void dfs(vector<vector<char>>& grid, int r, int c) {
            int nr = grid.size();
            int nc = grid[0].size();
    
            grid[r][c] = '0';
            if (r - 1 >= 0 && grid[r-1][c] == '1') dfs(grid, r - 1, c);
            if (r + 1 < nr && grid[r+1][c] == '1') dfs(grid, r + 1, c);
            if (c - 1 >= 0 && grid[r][c-1] == '1') dfs(grid, r, c - 1);
            if (c + 1 < nc && grid[r][c+1] == '1') dfs(grid, r, c + 1);
        }
    
    public:
        int numIslands(vector<vector<char>>& grid) {
            int nr = grid.size();
            if (!nr) return 0;
            int nc = grid[0].size();
    
            int num_islands = 0;
            for (int r = 0; r < nr; ++r) {
                for (int c = 0; c < nc; ++c) {
                    if (grid[r][c] == '1') {
                        ++num_islands;
                        dfs(grid, r, c);
                    }
                }
            }
    
            return num_islands;
        }
    };
    

    在这里插入图片描述

  • 省份数量: https://leetcode-cn.com/problems/number-of-provinces/
    在这里插入图片描述
    在这里插入图片描述

    class Solution {
    public:
        void dfs(vector<vector<int>>& isConnected, vector<int>& visited, int provinces, int i) {
            for (int j = 0; j < provinces; j++) {
                if (isConnected[i][j] == 1 && !visited[j]) {
                    visited[j] = 1;
                    dfs(isConnected, visited, provinces, j);
                }
            }
        }
    
        int findCircleNum(vector<vector<int>>& isConnected) {
            int provinces = isConnected.size();
            vector<int> visited(provinces);
            int circles = 0;
            for (int i = 0; i < provinces; i++) {
                if (!visited[i]) {
                    dfs(isConnected, visited, provinces, i);
                    circles++;
                }
            }
            return circles;
        }
    };
    

    在这里插入图片描述

6.3 回溯(Backtracking)

学习: https://zhuanlan.zhihu.com/p/54275352

一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。
在这里插入图片描述

  • 全排列: https://leetcode-cn.com/problems/permutations/
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    class Solution {
    public:
        void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){
            // 所有数都填完了
            if (first == len) {
                res.emplace_back(output);
                return;
            }
            for (int i = first; i < len; ++i) {
                // 动态维护数组
                swap(output[i], output[first]);
                // 继续递归填下一个数
                backtrack(res, output, first + 1, len);
                // 撤销操作
                swap(output[i], output[first]);
            }
        }
        vector<vector<int>> permute(vector<int>& nums) {
            vector<vector<int> > res;
            backtrack(res, nums, 0, (int)nums.size());
            return res;
        }
    };
    

    在这里插入图片描述

  • N 皇后: https://leetcode-cn.com/problems/n-queens/
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    class Solution {
    public:
        vector<vector<string>> solveNQueens(int n) {
            auto solutions = vector<vector<string>>();
            auto queens = vector<int>(n, -1);
            auto columns = unordered_set<int>();
            auto diagonals1 = unordered_set<int>();
            auto diagonals2 = unordered_set<int>();
            backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2);
            return solutions;
        }
    
        void backtrack(vector<vector<string>> &solutions, vector<int> &queens, int n, int row, unordered_set<int> &columns, unordered_set<int> &diagonals1, unordered_set<int> &diagonals2) {
            if (row == n) {
                vector<string> board = generateBoard(queens, n);
                solutions.push_back(board);
            } else {
                for (int i = 0; i < n; i++) {
                    if (columns.find(i) != columns.end()) {
                        continue;
                    }
                    int diagonal1 = row - i;
                    if (diagonals1.find(diagonal1) != diagonals1.end()) {
                        continue;
                    }
                    int diagonal2 = row + i;
                    if (diagonals2.find(diagonal2) != diagonals2.end()) {
                        continue;
                    }
                    queens[row] = i;
                    columns.insert(i);
                    diagonals1.insert(diagonal1);
                    diagonals2.insert(diagonal2);
                    backtrack(solutions, queens, n, row + 1, columns, diagonals1, diagonals2);
                    queens[row] = -1;
                    columns.erase(i);
                    diagonals1.erase(diagonal1);
                    diagonals2.erase(diagonal2);
                }
            }
        }
    
        vector<string> generateBoard(vector<int> &queens, int n) {
            auto board = vector<string>();
            for (int i = 0; i < n; i++) {
                string row = string(n, '.');
                row[queens[i]] = 'Q';
                board.push_back(row);
            }
            return board;
        }
    };
    

    在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只搬烫手的砖

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值