搜索问题汇总

1、BFS

广度优先搜索一层一层地进行遍历,每层遍历都是以上一层遍历的结果作为起点,遍历一个距离能访问到的所有结点。遍历过的结点不能再次被遍历。

设 di 表示第 i 个节点与根节点的距离,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di <= dj。

应用场景:无权图的最短路径

程序实现:1、队列,用来存储每一轮遍历得到的节点;2、标记,对于遍历过的节点,应该将它标记,防止重复遍历。

leetcode例题:

搜索问题汇总_第1张图片

class Solution {
    public int shortestPathBinaryMatrix(int[][] grid) {
        if(grid==null||grid.length==0||grid[0].length==0) return -1;
        int m=grid.length,n=grid[0].length;
        //搜索时用来更新下一个点坐标
        int[][] dir={{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
        //存储每一轮遍历到的节点坐标
        Queue>queue=new LinkedList<>();
        //根节点入队
        queue.add(new Pair<>(0,0));
        //记录路径长度
        int pathLength=0;
        while(!queue.isEmpty()){
            //记录当前队列中的所有结点
            int size=queue.size();
            //经过一轮遍历,更新路径长度
            pathLength++;
            while(size-->0){
                //节点出队
                Paircur=queue.poll();
                int x=cur.getKey(),y=cur.getValue();
                //剪枝
                if(grid[x][y]==1){
                    continue;
                }
                //遍历到目标节点,返回
                if(x==m-1&&y==n-1){
                    return pathLength;
                }
                //标记该节点已被遍历
                grid[x][y]=1;
                for(int[] d:dir){
                    //更新当前节点的下一个可选节点
                    int new_x=x+d[0],new_y=y+d[1];
                    if(new_x<0||new_x>=m||new_y<0||new_y>=n){
                        continue;
                    }
                    //满足条件的下一轮节点入队
                    queue.add(new Pair<>(new_x,new_y));
                }
            }
        }
        return -1;
    }
}

2、DFS

广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历。而深度优先搜索在得到一个新节点时立即对新节点进行遍历,直到没有新节点了,此时返回。

解决问题:从一个节点出发,使用DFS对一个图进行遍历时,能够遍历到的节点都是从初始节点可达的,可用来求解这种可达性问题。

程序实现:1、栈,用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。可以使用递归栈。2、标记,和BFS一样同样需要对已经遍历过的节点进行标记。

leetcode例题:

搜索问题汇总_第2张图片

class Solution {
    private int m,n;
    private int[][] dir={{0,-1},{-1,0},{0,1},{1,0}};
    public int maxAreaOfIsland(int[][] grid) {
        if(grid==null||grid.length==0||grid[0].length==0){
            return 0;
        }
        m=grid.length;
        n=grid[0].length;
        int maxArea=0;
        for(int i=0;i=m||y<0||y>=n||grid[x][y]==0){
            return 0;
        }
        //标记已经遍历过
        grid[x][y]=0;
        int area=1;
        for(int[] d:dir){
            area+=dfs(grid,x+d[0],y+d[1]);
        }
        return area;
    }
}

3、Backtracking

Backtracking(回溯)属于DFS。普通DFS主要用在可达性问题,这种问题只要执行到特定的位置然后返回即可。而Backtracking主要用于求解排列组合问题,这种问题在执行到特定的位置返回之后还会继续执行求解过程。

程序实现注意问题:在访问一个元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;但是在递归返回时,需要将元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。

leetcode例题:

搜索问题汇总_第3张图片

class Solution {
    public List restoreIpAddresses(String s) {
        Listres=new ArrayList<>();
        StringBuilder sb=new StringBuilder();
        backtracking(0,sb,res,s);
        return res;
    }
    private void backtracking(int k,StringBuilder sb,Listres,String s){
        //递归结束条件
        if(k==4||s.length()==0){
            if(k==4&&s.length()==0){
                res.add(sb.toString());
            }
            return;
        }
        //对于255来说,依次截取2、25、255
        for(int i=0;i

 参考链接:https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E6%90%9C%E7%B4%A2.md

你可能感兴趣的:(数据结构与算法)