图的搜索类题目

3 篇文章 1 订阅
1 篇文章 0 订阅

图的遍历相对于树的的遍历更加复杂,图中的遍历问题大多是有多个原点的,而数的遍历我们只需要从根节点出发即可,其次,树是具有方向性的。而图的遍历中,倘若是无向图则不具有方向性。我们在遍历的同时必须对原数据加以处理,防止重复遍历。

图的深度优先遍历(DFS)

机器人的运动范围

class Solution {
    public int movingCount(int key, int rows, int cols)
    {
        Boolean[][] visited=new Boolean[rows][cols];
        for(int i=0;i<visited.length;i++){
            for(int j=0;j<visited[i].length;j++){
                visited[i][j]=false;
            }
        }
        return DFS(0,0,visited,rows,cols,key);
    }
    public int DFS(int i,int j,Boolean[][] visited,int r,int c,int key){
        if(i==r||j==c||visited[i][j]){
            return 0;
        }
        visited[i][j]=true;
        if(count(i)+count(j)>key){
            return 0;
        }
        return DFS(i+1,j,visited,r,c,key)+DFS(i,j+1,visited,r,c,key)+1;
        
        
    }
    public int count(int n){
        int sum=0;
        while(n>0){
            sum+=n%10;
            n/=10;
        }
        return sum;
    }
}

岛屿的最大面积

class Solution {
    public int maxAreaOfIsland(int[][] grid) {
            int max=0;
            int rows=grid.length;
            int cols=grid[0].length;
            Boolean visited[][]=new Boolean[rows][cols];
            for(int i=0;i<rows;i++){
                    for(int j=0;j<cols;j++){
                            if(grid[i][j]==1)
                            max=Math.max(DFS(i,j,grid),max);//max存放上一个岛屿的面积
                    }
            }
            return max;
    }
    public int DFS(int x,int y,int[][] grid){
            if(x<0 || y<0 || x>=grid.length || y>=grid[0].length||grid[x][y]==0){
                    return 0;
            }
            grid[x][y]=0;//将访问后的点的值设为0 防止重复访问
            int count=1;
            count+=DFS(x+1,y,grid);
            count+=DFS(x-1,y,grid);
            count+=DFS(x,y+1,grid);
            count+=DFS(x,y-1,grid);
            return count;

    }
}                                                         

这两道题都是关于图的遍历问题,所以我们可以使用BFS或者DFS两种方法。不同点在于第一个问题我们是单起点的从一个点遍历图得到答案。而第二个问题中 我是对图的遍历是多起点的(不同的岛屿因不相接而导致面积不同)。我们可以想象成这是一个非连通图,每一个由一组成的岛屿是一个连通分量,通过for循环不断更换节点最终达到访问全部图的目的。
在图的遍历中,为了防止重复检测某一个结点我们常需要对它进行标记。上面两个题中的标记。都修改了原始数据,假若我们需要重多个起点遍历图的原始数据,这样显然是不行的。我们可以根据深度优先遍历 递归的特点,并且搭配移动数组[dx[]=0,0,-1,1],dy[]=[-1,1,0,0]。在每一次遍历这个点的上下左右时储存这个点的值然后,再最后将其复原。

            char temp= board[i][j];
            board[i][j]='0';
             for(int l=0;l<4;l++){
                    int newx=i+dx[l];
                    int newy=j+dy[l];
                    if(newx>=0 &&  newx<board.length && newy>=0 ){
                            if(board[newx][newy]!='0'){
                                       flag=DFS(newx,newy,board,word,len+1);
                            }
                    }
            }
             board[i][j]=temp;
            

这样每当我们以一个新的起点遍历图时,所有的数据都没有被修改过。

图的广度优先遍历(BFS)

01矩阵

class Solution {
    public int[][] updateMatrix(int[][] mat) {
            Queue<int[]> queue=new LinkedList<>();
            for(int i=0;i<mat.length;i++){
                    for(int j=0;j<mat[0].length;j++){
                            if(mat[i][j]==0){
                                    queue.offer(new int[]{i,j});//队列存放的i,j数组相当于一个坐标。
                            }
                            else{
                                    mat[i][j]=-1;
                            }
                    }
            }
            int dx[]=new int[]{-1,1,0,0};
            int dy[]=new int[]{0,0,-1,1};//遍历图时所使用的方向矩阵。
            while(!queue.isEmpty()){
                    int[] p=queue.poll();
                    int x=p[0];
                    int y=p[1];
                    for(int i=0;i<4;i++){
                            int newx=x+dx[i];
                            int newy=y+dy[i];
                 if(newx>=0 &&newx<mat.length &&newy>=0&&newy<mat[0].length&&mat[newx][newy]==-1){
                            mat[newx][newy]=mat[x][y]+1;
                            queue.offer(new int[]{newx,newy});
                            }
                    }
            }
            return mat;
    } 
}

学习如何利用BFS的方法遍历矩阵,以及原地修改矩阵的值的方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值