搜索

一、广度优先搜索BFS

1. 二进制矩阵中的最短路径   难度:medium   Leetcode题号:1091

题目描述:

思路:典型的BFS,每次向外扩一圈,当第一次到达目标点时即为所求的最短路径长度

C++代码如下:

class Solution {
public:
    int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
        if(grid.size() == 0 || grid[0].size() == 0 || grid[0][0] == 1){
            return -1;
        }
        int dir[8][2] = {{1,-1}, {1,0}, {1,1}, {0,1}, {0,-1}, {-1,1}, {-1,0}, {-1,-1}};
        int m = grid.size();
        int n = grid[0].size();
        bool visit[m][n];
        memset(visit,false,sizeof(visit));
        queue<pair<int,int>> Q;
        Q.push(make_pair(0,0));
        visit[0][0] = true;
        int len = 0;
        while(!Q.empty()){
            int size = Q.size();
            len++;
            while(size-- > 0){
                int cur_x = Q.front().first;
                int cur_y = Q.front().second;
                Q.pop();
                for(int i = 0 ; i < 8; i++){
                    int next_x = cur_x + dir[i][0];
                    int next_y = cur_y + dir[i][1];
                    if(next_x == n && next_y == m){
                            return len;
                    }
                    if(next_x >= 0 && next_x < n && next_y >=0 && next_y < m && grid[next_x]                            [next_y] == 0 && !visit[next_x][next_y]){
                            Q.push(make_pair(next_x, next_y));
                            visit[next_x][next_y] = true;
                    }
                }
            }    
        }
        return -1;
    }
};

 

2. 完全平方数    难度:medium    Leetcode题号:279

题目描述:

思路:

把每个数看成图中的一个节点,若两个数的差为一个平方数,则这两个数对应的节点之间就有一条边,则该问题转变为求从数n对应的节点到数0对应的节点之间的最短路径长度

代码中的generateSquares()函数的作用是生成所有小于等于n的平方数

代码如下:

vector<int> generateSquares(int n){   //生成平方数
    int num = 1;
    int square = pow(num, 2);
    vector<int> res;
    while(square <= n){
        res.push_back(square);
        num++;
        square = pow(num, 2);
    }
    return res;
}
class Solution {
public:
    int numSquares(int n) {
        vector<int> squares = generateSquares(n);
        queue<int> Q;
        bool visit[n+1];
        memset(visit, false, sizeof(visit));
        int level = 0; //层数,即组成和的平方数个数
        Q.push(n);
        visit[n] = true;
        while(!Q.empty()){
            int size = Q.size();
            level++;//到了下一层
            while(size--){
                int cur = Q.front();
                Q.pop();
                for(int s : squares){
                    int next = cur - s;
                    if(next < 0){
                        break;//由于squares是升序的,故当一个差为负时没必要继续判断之后的了
                    } else if(next == 0){
                        return level; //到达了0节点直接返回最短路径长度
                    } else if(!visit[next]){
                        visit[next] = true;
                        Q.push(next);
                    }
                }
            }
        }
        return n;
    }
};

 

二、深度优先搜索DFS

1. 岛屿的最大面积   难度:medium   Leetcode题号:695

题目链接:https://leetcode-cn.com/problems/max-area-of-island/description/

题目描述:

思路:典型的dfs,对每个坐标的上下左右进行搜索,取找到的1的个数的最大值,注意当搜索到一个值为1的位置后,应将其值置为0(类似于将标记位置为1),然后再扩展进一步搜索

C++代码如下:

class Solution {
public:
    int direction[4][2] = {{0,1}, {0,-1}, {-1,0}, {1,0}};
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        if(grid.size()==0 || grid[0].size()==0){
            return 0;
        }
        int m = grid.size();
        int n = grid[0].size();
        int maxArea = 0;
        for(int i = 0 ; i < m ; i++){
            for(int j = 0; j < n; j++){
                maxArea = max(maxArea, dfs(grid, i, j));
            }
        }
        return maxArea;
    }
    int dfs(vector<vector<int>>& grid, int x, int y){
        if(x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size() || grid[x][y] == 0){
            return 0;
        }
        grid[x][y] = 0;
        int area = 1;
        for(int i = 0 ; i < 4 ; i++){
            int next_x = x + direction[i][0];
            int next_y = y + direction[i][1];
            area += dfs(grid, next_x, next_y);
        }
        return area;
    }
};

 

2. 岛屿数量(求连通分支数)  难度:medium   Leetcode题号:200

题目链接:https://leetcode-cn.com/problems/number-of-islands/description/

题目描述:

显然本题目是求解矩阵中的连通分支数目,思路如下:

(1)当找到一个值为1的元素时,首先将连通分支数加1,然后将该元素置为0,然后对其上下左右四个元素应用dfs,执行相同的过程,若元素本来就是0,则可以直接返回;这样运行一次完整的dfs就会将一个连通分支中的所有元素变为0,

(2)以后每遍历到一个值为1的元素,则表明有新的连通分支出现了,重复(1)过程即可

C++代码如下:

class Solution {
public:
    int direction[4][2] = { {0,1}, {0,-1}, {1,0}, {-1,0}};
    int m , n;
    int numIslands(vector<vector<char>>& grid) {
        if(grid.size() == 0 || grid[0].size() == 0){
            return 0;
        }
        m = grid.size();
        n = grid[0].size();
        int ans = 0;
        for(int i = 0 ; i < m ; i++){
            for(int j = 0; j < n ; j++){
                if(grid[i][j] == '1'){
                    ans++;
                    dfs(grid, i , j);
                }
            }
        }
        return ans;
    }
    void dfs(vector<vector<char>>& grid, int x, int y){
        if(x < 0 || x >= m || y < 0 || y >=n || grid[x][y] == '0'){
            return ;
        }
        grid[x][y] = '0';
        for(int i = 0 ; i < 4; i++){
            int next_x = x + direction[i][0];
            int next_y = y + direction[i][1];
            dfs(grid, next_x, next_y);
        }
    }
};

 

3.  朋友圈   难度:medium   Leetcode题号:547

题目链接:https://leetcode-cn.com/problems/friend-circles/description/

题目描述:

 

dfs代码:

class Solution {
public:
    int n;
    int findCircleNum(vector<vector<int>>& M) {
        if(M.size() == 0 || M[0].size() == 0){
            return 0;
        }
        n = M.size();
        bool visit[n];
        memset(visit, false, sizeof(visit));
        int ans = 0;
        for(int i = 0 ; i < n ; i++){
            if(!visit[i]){
                ans++;
                dfs(M, visit, i);
            }
        }
        return ans;
    }
    void dfs(vector<vector<int>>& M, bool visit[], int x){
        if(visit[x]){
            return;
        }
        visit[x] = true;
        for(int i = 0; i < M.size(); i++){
            if(!visit[i] && M[x][i] == 1){
                dfs(M, visit, i);
            }
        }
    }
};

 

4. 被围绕的区域   难度:medium   Leetcode题号:130

题目链接:

https://leetcode-cn.com/problems/surrounded-regions/submissions/

题目描述:

思路:

由题目解释可知,在矩阵边界上的'O'以及与其在一个连通分支(即与其直接或间接可达)的'O'不会被填充,那么可以分两步进行:

(1)对边界上所有'O'进行一遍dfs,将它所在的连通分支所有'O'元素都用'-'替代('-'可以是除了'X'和'O'之外的任意一种字符)

(2)(1)过程执行完之后,所有应被填充的元素值没有变,仍是'O',故应将填充为为'X',而'-'是不应被填充的元素,故应将其重置为'O'

C++ dfs代码如下:

class Solution {
public:
    int direction[4][2] = { {1,0},{-1,0},{0,1},{0,-1}};
    int m, n;
    void solve(vector<vector<char>>& board) {
        if(board.size() == 0 || board[0].size() == 0){
            return ;
        }
        m = board.size();
        n = board[0].size();
        for(int i = 0 ; i < m; i++){
            for(int j = 0 ; j < n; j++){
                if(i == 0 || i == m - 1 || j == 0 || j == n - 1 ){
                    if(board[i][j] != 'O'){
                        continue;
                    }
                    dfs(board, i , j);
                }
            }
        }
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n; j++){
                if(board[i][j] == 'O'){
                    board[i][j] = 'X';
                } else if(board[i][j] == '-'){
                    board[i][j] = 'O';
                }
            }
        }
    }
    void dfs(vector<vector<char>>& board, int x, int y){
        if(x < 0 || x >= m || y < 0 || y>=n || board[x][y] != 'O'){
            return ;
        }
        board[x][y] = '-';
        for(int i = 0; i < 4; i++){
            int next_x = x + direction[i][0];
            int next_y = y + direction[i][1];
            dfs(board, next_x, next_y); 
        }
    }
};

 

5. 太平洋大西洋水流问题  难度:medium Leetcode题号:417

题目链接:

https://leetcode-cn.com/problems/pacific-atlantic-water-flow/

题目描述:

思路:

与第上题被填充的区域类似,该题同样应考虑从边界逆流而上去寻找连通分支,只不过这里的联通分支要求每个坐标的高度要非递减(即下一个坐标高度要大于等于当前坐标高度),另外,需要设置两个坐标的标记数组(这里使用vector),分别记录能否从太平洋和大西洋到达该坐标,然后分别从太平洋和大西洋逆流而上进行dfs,最后遍历所有坐标的两个标记值,若都为true则表示从两个大洋都能到达该坐标(即从该坐标能到达两个大洋)

C++ dfs代码如下:

class Solution {
public:
    int m,n;
    int direction[4][2]= {{0,1}, {0,-1}, {1,0}, {-1,0}}; //四个水流方向
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& matrix) {
        vector<vector<int>> ans;//结果集合
        if(matrix.size() == 0 || matrix[0].size() == 0){
            return ans;
        }
        m = matrix.size();
        n = matrix[0].size();
        vector<vector<bool>> canReachP(m, vector<bool>(n,false));//能从太平洋回流到的标志
        vector<vector<bool>> canReachA(m, vector<bool>(n,false));//能从大西洋回流到的标志
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(i == 0 || j == 0){ //从与太平洋连接的坐标开始逆流而上寻找
                    dfs(matrix, canReachP, i, j);
                } 
                if(i == m-1 || j == n-1){ //从与大西洋连接的坐标开始逆流而上寻找
                    dfs(matrix, canReachA, i, j);
                }
            }
        }
        for(int i = 0 ; i < m; i++){
            for(int j = 0; j < n; j++){
                if(canReachA[i][j] && canReachP[i][j]){ //若两个大洋都能逆流到该坐标
                    ans.push_back({i,j});
                }
            }
        }
        return ans;
    }
    bool judge(int x,int y){ //判断坐标是否在合法范围内
        return x>=0 && x<m && y>=0 && y<n;
    }
    void dfs(vector<vector<int>>& matrix, vector<vector<bool>>& canReach, int x, int y){
        if(canReach[x][y]){
            return ;
        }
        canReach[x][y] = true;
        for(int i = 0 ; i < 4; i++){
            int next_x = x + direction[i][0];
            int next_y = y + direction[i][1];
            //由于是逆流而上,所以要找高度比当前坐标大或相等的
            if(judge(next_x, next_y) && matrix[next_x][next_y] >= matrix[x][y]){ 
                dfs(matrix, canReach, next_x, next_y);
            }
        }
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值