LeetCode指北-BFS

BFS就是广度优先算法,BFS相对DFS来说不太直观。BFS中,我们会搜索r的“孙子节点”之前先访问结点r的所有相邻结点。一般用队列+迭代方案实现。

为了复习下BFS的思想,看下BFS最基本的场景=。=
无向图的BFS来举栗子
BFS是“地毯式”层层递进的搜索策略,先查找离起始顶点最近的,依次往外搜索。下图表示了搜索的过程,盗一张大佬的图。

其实思想不复杂,实现起来还是要琢磨一下的。

前面提到BFS要用队列+迭代方案实现,那么我们需要三个辅助变量visited,queue,prev

visited:记录以及访问过的顶点,避免顶点被重复访问
queue:关键的是这里,实现的是记录功能,因为是层层递进,需要暂存访问过的顶点,方便进行下一层搜索
prev:记录搜索过的路径,不过是反向存储的,prev[w]存储的是从哪个前驱顶点遍历过来的。关注下print函数的实现。

talk is cheap,show you the code:

public class BFS {
    public int v;//顶点个数
    public LinkedList adj[];// 邻接表

    public BFS(int v) {
        this.v = v;
        adj = new LinkedList[v];
        for (int i = 0; i < v; ++i) {
            adj[i] = new LinkedList<>();
        }
    }

    // 添加连接关系
    public void addEdge(int s, int t) {
        adj[s].add(t);
        adj[t].add(s);
    }

    // bfs搜索,s到t的路径
    public void bfs(int s, int t) {
        // s,t是同一节点,返回
        if (s == t) {
            return;
        }

        //三大辅助变量---visited
        boolean[] visited = new boolean[v];

        // 三大辅助变量---queue
        Queue queue = new LinkedList<>();

        // 加入s
        queue.add(s);

        // 三大辅助变量-- prev
        int[] prev = new int[v];

        // 初始化为-1
        for (int i = 0; i < v; ++i) {
            prev[i] = -1;
        }

        while (queue.size() != 0) {
            // 堆顶出队
            int w = queue.poll();

            // 遍历w的临接节点
            for (int i = 0; i < adj[w].size(); ++i) {
                //和w相邻的一个节点
                int q = adj[w].get(i);
                // 如果q没有访问过
                if (!visited[q]) {
                    // 记录prev,q的上前驱节点是w
                    prev[q] = w;
                    // 到终点了打印路径
                    if (q == t) {
                        print(prev, s, t);
                        return;
                    }
                    // q访问过了,标记
                    visited[q] = true;
                    // 将q加入队列
                    queue.add(q);
                }
            }
        }

    }

    // 递归打印从终点t到起点的路径
    private void print(int[] prev, int s, int t) {
        if (prev[t] != -1 && t != s) {
            print(prev, s, prev[t]);
        }
        System.out.print(t + " ");
    }
}

其实呢,要记住模板~编码5分钟,调试两小时,再放一个方便记忆的模板,也方便手写

void search(Node root) {
        Queue queue = new Queue();
        root.visited = true;
        visit(root);
        queue.add(root); // 加至队列尾部
      
       while(!queue.isEmpty())  {
           Node r = queue.poll(); //从队列头部移除
           foreach(Node n in r.adjacent) {
                if(n.visited == false) {
                    visit(n);
                    n.visited = true;
                    queue.add(n);
                }
          }
      }
}

下面实操一下,看看LeetCode真题


最短路径的题,“地毯式搜索”,广度优先返回的就是最短路线

  • visited数组,记录访问过的数字,是从0到n
  • queue 这里存放的挑选后剩余的总和n,以及已选数字的个数
  • 满足条件时,返回
  • 用java写感觉有点啰嗦,=。=
    public int numSquares(int n) {
        if (n == 0) {
            return 0;
        }

        // 暂存队列,每一种元素有剩余总数和已选元素个数组成
        Deque> queue = new LinkedList>();
        ArrayList list = new ArrayList(2);
        list.add(n);
        list.add(0);
        queue.add(list);

        boolean[] visited = new boolean[n + 1];
        visited[n] = true;

        while (!queue.isEmpty()) {
            ArrayList temp = queue.removeFirst();
            int remain = temp.get(0);
            int step = temp.get(1);
            if(remain == 0) {
                return step;
            }
            for (int i = 1; remain - i * i >= 0; i++) {
                int a = remain - i * i;
                if (!visited[a]) {
                    if (a == 0) {
                        return step+1;
                    }
                    ArrayList tempList = new ArrayList(2);
                    tempList.add(a);
                    tempList.add(step + 1);
                    queue.addLast(tempList);
                    visited[a] = true;
                }

            }
        }
        return 0;
    }

再看一题:


根据题目的意思,就是要广搜来遍历对应id的员工所有impance的值

  • 使用了java 8的stream来筛选出对应id的employee的信息
       public int getImportance(List employees, int id) {
        int result = 0;
        Employee rootEmployee = new Employee();
        Queue queue = new LinkedList<>();
        rootEmployee = getEmployeeById(employees, id);
        queue.offer(rootEmployee);
        while (!queue.isEmpty()) {
            Employee employee = queue.poll();
            result += employee.importance;
            for (Integer subordinate : employee.subordinates) {
                queue.offer(getEmployeeById(employees, subordinate));
            }
        }
        return result;

    }

    private Employee getEmployeeById(List employees, int id) {
        return employees.stream().filter(employee -> employee.id == id).collect(Collectors.toList()).get(0);
    }

你可能感兴趣的:(LeetCode指北-BFS)