leetcode 刷题day01

解题方法一:深度优先搜索

我们可以将二维网格看成一个无向图,竖直或水平相邻的 1 之间有边相连。

为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1,则以其为起始节点开始进行深度优先搜索。在深度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。

最终岛屿的数量就是我们进行深度优先搜索的次数。

//深度优先搜索
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;
    }
};

解题方法二:广度优先搜索

同样地,我们也可以使用广度优先搜索代替深度优先搜索。

为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1,则将其加入队列,开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。直到队列为空,搜索结束。

//广度优先搜索 队列
class Solution {
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;
                    grid[r][c]='0';
                    queue<pair<int,int>> neighbors;
                    neighbors.push({r,c});
                    while(!neighbors.empty()){
                        auto rc=neighbors.front();
                        neighbors.pop();
                        int row = rc.first,col=rc.second;
                        if(row-1>=0 && grid[row-1][col]=='1'){
                            neighbors.push({row-1,col});
                            grid[row-1][col] = '0';
                        }
                        if(row+1<nr && grid[row+1][col]=='1'){
                            neighbors.push({row+1,col});
                            grid[row+1][col] = '0';
                        }
                        if(col-1>=0 && grid[row][col-1]=='1'){
                            neighbors.push({row,col-1});
                            grid[row][col-1] = '0';
                        }
                        if(col+1<nc && grid[row][col+1]=='1'){
                            neighbors.push({row,col+1});
                            grid[row][col+1] = '0';
                        }
                    }
                }
            }
        }
        return num_islands;
    }
};

方法一:位移

算法

如上述所说,算法由两个步骤组成:

我们通过右移,将两个数字压缩为它们的公共前缀。在迭代过程中,我们计算执行的右移操作数。
将得到的公共前缀左移相同的操作数得到结果。

//位移
class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int shift = 0;
        // 找到公共前缀
        while (m < n) {
            m >>= 1;
            n >>= 1;
            ++shift;
        }
        return m << shift;
    }
};

方法二:Brian Kernighan算法

//Brian Kernighan算法
class Solution{
public:
    int rangeBitwiseAnd(int m,int n){
        while(m<n){
            n = n & (n-1);
        }
        return n;
    }
};

 Brian Kernighan算法的衍生题目:

 方法一:移位实现位计数(造轮子)

//位移
class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int shift = 0;
        // 找到公共前缀
        while (m < n) {
            m >>= 1;
            n >>= 1;
            ++shift;
        }
        return m << shift;
    }
};

方法二:Brian Kernighan算法

还有一个位移相关的算法叫做「Brian Kernighan 算法」,它用于清除二进制串中最右边的 1。

Brian Kernighan 算法的关键在于我们每次对 number 和 number−1 之间进行按位与运算后,number 中最右边的 1 会被抹去变成 0。

//Brian Kernighan算法
class Solution{
public:
    int rangeBitwiseAnd(int m,int n){
        while(m<n){
            n = n & (n-1);
        }
        return n;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值