Topological Sorting(拓扑排序必考题)

http://www.lintcode.com/en/problem/topological-sorting/


题目:将图中节点进行拓扑排序(假设图中至少存在一个拓扑序列)

         class DirectedGraphNode {
               int label;
               ArrayList<DirectedGraphNode> neighbors;
              DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
         };   

(DirectedGraphNode类中的neighbor元素表示该节点指向的节点,即出度)


解答:主要分为三步:

          1、统计所有节点的入度(indegree);

          2、将所有入度为0的点放入队列中;

          3、BFS(根据pop出的点,重新计算节点入度,将入度为0的点加入队列中)


代码:

public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
        // write your code here
        if (graph == null) {
            return graph;
        }
        
        ArrayList<DirectedGraphNode> res = new ArrayList<>();
        Map<DirectedGraphNode, Integer> map = new HashMap<>();
        
        for (DirectedGraphNode node : graph) {
            for (DirectedGraphNode neighbor : node.neighbors) {
                if (map.containsKey(neighbor)) {
                    map.put(neighbor, map.get(neighbor) + 1);
                } else {
                    map.put(neighbor, 1);
                }
            }
        }
        
        Queue<DirectedGraphNode> queue = new LinkedList<>();
        
        for (DirectedGraphNode node : graph) {
            if (!map.containsKey(node)) {
                queue.offer(node);
                res.add(node);
            }
        }
        
        while (!queue.isEmpty()) {
            DirectedGraphNode head = queue.poll();
            for (DirectedGraphNode neighbor : head.neighbors) {
                map.put(neighbor, map.get(neighbor) - 1);
                if (map.get(neighbor) == 0) {
                    queue.offer(neighbor);
                    res.add(neighbor);
                }
            }
        }
        return res;
    }

          

变题一:Course Schedule

https://leetcode.com/problems/course-schedule/description/

题目:总共需要修n门课程(0 - n-1),有些课需要有先修课程,如[0, 1]表示上课程1必须先上课程0。输入总共需要修的课程总数和先修课程组合,判断能否修完全部课程;

解答:方法同上(拓扑排序三步法)


改进:无需加入list再得到最后list的长度,直接技术即可;


代码:

public boolean canFinish(int numCourses, int[][] prerequisites) {
        Map<Integer, Integer> map = new HashMap<>();
        Queue<Integer> queue = new LinkedList<>();
        int counter = 0;
        
        if (prerequisites == null && prerequisites.length == 0) return true;
        
        //put courses that have prerequisites and their num of indegrees into map
        for (int i = 0; i < prerequisites.length; i++) {
            if (map.containsKey(prerequisites[i][0])) {
                map.put(prerequisites[i][0], map.get(prerequisites[i][0]) + 1);
            } else {
                map.put(prerequisites[i][0], 1);
            } 
        }
        
        //put courses whose indegree is zero into the queue
        for (int i = 0; i < numCourses; i++) {
            if (!map.containsKey(i)) {
                queue.offer(i);
            }
        }
        
        //pop current node in queue and recalculate the indegree relates to it
        while (!queue.isEmpty()) {
            int node = queue.poll();
            counter++;
            
            for (int i = 0; i < prerequisites.length; i++) {
                if (node == prerequisites[i][1]) {
                    if (map.get(prerequisites[i][0]) == 1) {
                        queue.offer(prerequisites[i][0]);
                    } else {
                        map.put(prerequisites[i][0], map.get(prerequisites[i][0]) - 1);
                    }
                }
            }    
        }
        if (counter == numCourses) return true;
        else return false;
    }


变题二:Course ScheduleII

https://leetcode.com/problems/course-schedule-ii/description/

题目:同上,输出修全部课程的先后顺序;

解答:同上,输出结果更改即可;


变题三:Sequence Reconstruction

https://leetcode.com/problems/sequence-reconstruction/description/

题目:输入org序列、seqs序列集合,判断org是否是seqs集合中所有序列的最短父序列;

解答:1、设置两个HashMap: HashMap1<元素,指向的下个元素>, HashMap2<元素,自由度>;

           2、填充两个HashMap,遇到org中不存在的元素直接返回false;遍历seqs中元素时用count3计数,若count3比org长度小,说明org肯定不是最短父序列,所以返回false;

           3、遍历HashMap2, 将自由度为0的点放入队列(为保证唯一性,每次遍历只有一个自由度为0的点),将该点指向的所有下个元素自由度减1。


第一次犯错:未考虑seqs最短父序列不为1的情况。通过控制每次遍历自由度为0的数只有一个来避免;

第二次犯错:未考虑seqs存在org没有的元素。若出现org没有的元素,直接返回false;

第三次犯错:未考虑seqs为空的情况。统计seq中所有元素个数,若小于org长度则返回false;

第四次犯错:与第一次犯错相似,未考虑一开始队列存在多个自由度为0的元素;

第五次犯错:与第二次犯错相似,因为循环从第二个数开始,为考虑第一个数是否存在于org之中。在循环前面增加判断条件,需注意seq.get(0)需要在seq.size() > 0的情况下才可以进行。


代码:

public boolean sequenceReconstruction(int[] org, List<List<Integer>> seqs) {
        Map<Integer, Set<Integer>> map = new HashMap<>();
        Map<Integer, Integer> indegree = new HashMap<>();
        int count = 0;
        int count3 = 0;
        
        for (int i = 0; i < org.length; i++) {
            map.put(org[i], new HashSet<>());
            indegree.put(org[i], 0);
        }
        
        for (List<Integer> seq : seqs) {
             count3 += seq.size();
            if (seq.size() > 0 && !map.containsKey(seq.get(0))) {
                    return false;
            } 
            for (int i = 1; i < seq.size(); i++) {
                int temp = seq.get(i);
                if (!map.containsKey(temp)) {
                    return false;
                } 
                if (map.get(seq.get(i - 1)).add(temp)) {
                    indegree.put(temp, indegree.get(temp) + 1);
                }        
            }
        }
        
        if (count3 < org.length) {
            return false;
        }
        
        Queue<Integer> queue = new LinkedList<>();
        
        int count4 = 0;
        
        for (int i = 0; i < org.length; i++) {
            if (indegree.get(org[i]) == 0) {
                count4++;
                queue.offer(org[i]);
                if (org[count++] != org[i]) {
                    return false;
                }
            }
        }
        
        if (count4 > 1) {
            return false;
        }
        
        while (!queue.isEmpty()) {
            int head = queue.poll();
            int count2 = 0;
            for (int n : map.get(head)) {
                indegree.put(n, indegree.get(n) - 1);
                if (indegree.get(n) == 0) {
                    count2++;
                    queue.offer(n);
                    if (org[count++] != n) {
                        return false;
                    }
                }
            }
            if (count2 > 1) {
                return false;
            }
        }
        
        if (count != org.length) { 
            return false;
        }
        
        return true;
    }



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值