【广度优先搜索】BFS解决拓扑排序:课程表I,课程表II,火星词典

文章目录

拓扑排序

借助队列,一次BFS即可

  1. 初始化,把所有AOV网中入度为0的点加入到队列中
  2. 当队列不为空时:
    1. 拿出队头元素放到结果中
    2. 删除与该节点相连的边
    3. 判断:与删除边相连的节点是否入度变成0,如果入度为0,加入到队列中

建图:

  1. List<List<Integer>或者Map<Integer,List<Integer>>实现领接表
  2. 利用数组int[] in = new int[n]存储每个节点的入度

1. 课程表(LC207)

课程表

题目描述

代码实现

java 复制代码
class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        Queue<Integer> queue = new LinkedList<>();
        //统计入度
        int[] in = new int[numCourses];
        //邻接表存图
        Map<Integer,List<Integer>> edge = new HashMap<>();

        //建图
        for(int i =0;i<prerequisites.length;i++){
            //b->a
            int a = prerequisites[i][0];
            int b = prerequisites[i][1];
            if(!edge.containsKey(b))
                edge.put(b,new ArrayList<>());
            edge.get(b).add(a);
            in[a]++;
        }

        //拓扑排序
        //1.把入度为0 的点加入到队列中
        for(int i = 0;i<numCourses;i++){
            if(in[i]==0)
                queue.offer(i);
        }
        //bfs
        while(!queue.isEmpty()){
            int t = queue.poll();
            //遍历当前点所连接的下一个节点,让它们入度-1
            for(int a : edge.getOrDefault(t,new ArrayList<>())){
                in[a]--;
                if(in[a]==0)
                    queue.offer(a);
            }
        }

        //判断是否有环
        for(int a :in){
            if(a!=0)
                return false;
        }
        return true;
    }
}

2. 课程表II(LC210)

课程表II

题目描述

解题思路

在出队时统计拓扑排序

代码实现

java 复制代码
class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int index = 0;
        int[] ret = new int[numCourses];
        Queue<Integer> queue = new LinkedList<>();
        Map<Integer,List<Integer>> map = new HashMap<>();
        int[] in = new int[numCourses];

        //建图
        for(int i = 0;i<prerequisites.length;i++){
            int a = prerequisites[i][0];
            int b = prerequisites[i][1];
            if(!map.containsKey(b))
                map.put(b,new ArrayList());
            map.get(b).add(a);
            in[a]++;
        }

        //拓扑排序
        for (int i = 0; i < numCourses; i++) { 
            if (in[i] == 0) {
                queue.offer(i);
            }
        }

        //bfs
        while(!queue.isEmpty()){
            int t = queue.poll();
            ret[index++]=t;
            for(int a : map.getOrDefault(t,new ArrayList<>())){
                in[a]--;
                if(in[a]==0)
                    queue.offer(a);
            }
        }

        if(index==numCourses)
            return ret;
        return new int[0];
    }
}

3. 火星词典(LCR114)

火星词典

题目描述

解题思路

  1. 收集信息:两层for循环,统计所有的字母组合。

  2. 拓扑排序:

    1. 建图:利用Map<Charater , Set<Character>> 存放边的信息。不直接用List,而是要换成Set,防止重复的信息干扰
    2. 统计入度信息:Map<Character,Integer>,数组可以自动初始化为0,而哈希表必须手动初始化所有的节点入度为0
  3. 判断字典序:一个指针分别遍历两个字符串,当指针遇到不同字符时,前面的字符比后面的字典序小。如果遇到类似abc,ab这种前长后短的字符串,可以直接判定为无效。

代码实现

java 复制代码
class Solution {
    public String alienOrder(String[] words) {
        HashMap<Character,HashSet<Character>> edges = new HashMap<>();
        HashMap<Character,Integer> in = new HashMap<>();
        StringBuilder ret = new StringBuilder();

        //初始化哈希表入度,把所有字符的入度都置为0
        for(String s:words){
            for(int i = 0;i<s.length();i++)
                in.put(s.charAt(i),0);
        }

        //收集信息
        for(int i = 0;i<words.length;i++){
            for(int j = i+1;j<words.length;j++){
                String a = words[i];
                String b = words[j];

                int index = 0;
                while(index<a.length() && index<b.length() && a.charAt(index) == b.charAt(index))
                    index++;

                //a包含b且a比b长,非法
                if(index<a.length() && index==b.length())
                    return "";
                
                //字母不同,判断字典序
                if(index<a.length() && index<b.length()){
                    char ch1 = a.charAt(index);
                    char ch2 = b.charAt(index);
                    //ch1 < ch2

                    if(!edges.containsKey(ch1))
                        edges.put(ch1,new HashSet<Character>()); 
                    
                    if(!edges.get(ch1).contains(ch2)){
                        edges.get(ch1).add(ch2);
                        in.put(ch2,in.get(ch2)+1);
                    }
                }
            }
        }
        //  拓扑排序
        Queue<Character> queue = new LinkedList<>();
        //把所有入度为0的节点放入队列中
        for(char ch :in.keySet()){
            if(in.get(ch)==0)
                queue.offer(ch);
        }

        while(!queue.isEmpty()){
            char top = queue.poll();
            ret.append(top);

            for(char ch:edges.getOrDefault(top,new HashSet<>())){
                in.put(ch,in.get(ch)-1);
                if(in.get(ch)==0)
                    queue.offer(ch);
            }
        }
        for(char ch :in.keySet()){
            if(in.get(ch)!=0)
                return "";
        }
        return ret.toString();
    }
}
相关推荐
人道领域2 小时前
LeetCode【刷题日记】:滑动窗口算法详解:从暴力法到最优解
java·算法·leetcode
凤年徐2 小时前
封装红黑树实现 mymap 和 myset
网络·c++·算法
秃头狂魔2 小时前
【HOT100】DAY1
算法·哈希算法
MicroTech20252 小时前
MLGO微算法科技分布式量子算法模拟技术:以动态量子电路推动可扩展量子计算
科技·算法·量子计算
实名上网宋凯宣2 小时前
水电参与电力市场研究(2)_内含代码
算法·电力市场
不知名的老吴2 小时前
“程序 = 算法 + 数据结构”的拓展与启示
算法
阿i索2 小时前
【蓝桥杯备赛Day4】基础算法
笔记·算法·蓝桥杯
96772 小时前
多线程编程:整个互斥的流程以及scoped_lock的用法,以及作用,以及 硬件上的原子操作和逻辑上的原子操作
开发语言·c++·算法
liuyao_xianhui2 小时前
优选算法_topk问题_快速排序算法_堆_C++
java·开发语言·数据结构·c++·算法·链表·排序算法