leetcode图

来源:互联网 发布:dnf台服数据库爆率修改 编辑:程序博客网 时间:2024/05/22 14:52

leetcode图的相关题目解析:
对图的遍历就是两个经典的方法DFS和BFS。BFS经常用Queue实现,DFS经常用递归实现(可改为栈实现)。

1、Clone Graph
题意:给定图中一个节点,克隆图
思路:用HashMap,key存lable值,value存新clone的node,用BFS方法遍历帮助拷贝neighbors的值。给定给一个节点,若lable在map中有,则表示已经clone;若没有,则将当前节点加入map中,一次clone节点的邻居节点。
代码:

class UndirectedGraphNode {    int label;    List<UndirectedGraphNode> neighbors;    UndirectedGraphNode(int x) {        label = x;        neighbors = new ArrayList<UndirectedGraphNode>();    }}
    private HashMap<Integer, UndirectedGraphNode> map = new HashMap<>();    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {        return clone(node);    }    private UndirectedGraphNode clone(UndirectedGraphNode node) {        if (node == null) return null;        if (map.containsKey(node.label)) {            return map.get(node.label);        }        UndirectedGraphNode clone = new UndirectedGraphNode(node.label);        map.put(clone.label, clone);        for (UndirectedGraphNode neighbor : node.neighbors) {            clone.neighbors.add(clone(neighbor));        }        return clone;    }

2、Evaluate Division
题意:以算式A / B = k的形式给出若干等式,其中A和B是以字符串表示的变量,k是实数(浮点数)。给定一些查询,返回结果。如果答案不存在,返回 -1.0
Given a / b = 2.0, b / c = 3.0.
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? .
return [6.0, 0.5, -1.0, 1.0, -1.0 ].

思路:输入等式可以看做一个有向图,例如等式a / b = 2.0,可以转化为两条边:

    public double[] calcEquation(String[][] equations, double[] values, String[][] queries) {        // build graph, use adjacent list        map = new HashMap();        for(int i = 0; i < equations.length; i++) {            String[] equation = equations[i];            if(!map.containsKey(equation[0])) map.put(equation[0], new ArrayList());            map.get(equation[0]).add(new Info(equation[1], values[i]));            if(!map.containsKey(equation[1])) map.put(equation[1], new ArrayList());            map.get(equation[1]).add(new Info(equation[0], 1 / values[i]));        }        double[] result = new double[queries.length];        for(int i = 0; i < result.length; i++) {            result[i] = find(queries[i][0], queries[i][1], 1, new HashSet());        }        return result;    }    HashMap<String, List<Info>> map;    private double find(String start, String end, double value, Set<String> visited) {        if(visited.contains(start)) return -1;        if(!map.containsKey(start)) return -1;        if(start.equals(end)) return value;        visited.add(start);        for(Info next : map.get(start)) {            double sub = find(next.den, end, value * next.val, visited);            if(sub != -1.0) return sub;        }        visited.remove(start);        return -1;    }    class Info {        String den;        double val;        Info(String den, double val) { this.den = den; this.val = val; }    }

3、题目:Reconstruct Itinerary
题意:tickets = [[“MUC”, “LHR”], [“JFK”, “MUC”], [“SFO”, “SJC”], [“LHR”, “SFO”]]
Return [“JFK”, “MUC”, “LHR”, “SFO”, “SJC”].

思路:存储在hash中,并且使用PriorityQueue来排序。等我们图建立好了以后,从节点JFK开始遍历,只要当前节点映射的multiset里有节点,我们取出这个节点,将其在multiset里删掉,然后继续递归遍历这个节点,由于题目中限定了一定会有解,那么等图中所有的multiset中都没有节点的时候,我们把当前节点存入结果中(头插形式),然后再一层层回溯回去。public List<String> findItinerary(String[][] tickets) {    for (String[] ticket : tickets)        targets.computeIfAbsent(ticket[0], k -> new PriorityQueue()).add(ticket[1]);    visit("JFK");    return route;}Map<String, PriorityQueue<String>> targets = new HashMap<>();List<String> route = new LinkedList();void visit(String airport) {    while(targets.containsKey(airport) && !targets.get(airport).isEmpty())        visit(targets.get(airport).poll());    route.add(0, airport);}

4、Minimum Height Trees
题意:给定一系列边,寻找使得树高度最小的根节点
思路:从叶节点开始寻找,寻找离所有叶节点最远的节点,则为根。每次去掉当前图的所有叶子节点,重复此操作直到只剩下最后的根。

    public List<Integer> findMinHeightTrees(int n, int[][] edges) {    if (n == 1) return Collections.singletonList(0);    //构建邻接表    List<Set<Integer>> adj = new ArrayList<>(n);    for (int i = 0; i < n; ++i) adj.add(new HashSet<>());    for (int[] edge : edges) {        adj.get(edge[0]).add(edge[1]);        adj.get(edge[1]).add(edge[0]);    }    //找到所有叶子结点,所有入度(即相连边数)为 1 的节点即是叶子节点。    List<Integer> leaves = new ArrayList<>();    for (int i = 0; i < n; ++i)        if (adj.get(i).size() == 1) leaves.add(i);    //找高度最小的节点,即找离所有叶子节点最远的节点,也即找最中心的节点。    while (n > 2) {        n -= leaves.size();        List<Integer> newLeaves = new ArrayList<>();        for (int i : leaves) {            //每次去掉当前图的所有叶子节点,重复此操作直到只剩下最后的根。            int j = adj.get(i).iterator().next();            adj.get(j).remove(i);            if (adj.get(j).size() == 1) newLeaves.add(j);        }        leaves = newLeaves;    }    return leaves;       }

5、Course Schedule
题意:2, [[1,0],[0,1]],代表有两个课程,0的先行课是1,1的先行课的是0,不可能,输出false。
翻译:在一个有向图中,每次找到一个没有前驱节点的节点(也就是入度为0的节点),然后把它指向其他节点的边都去掉,重复这个过程(BFS),直到所有节点已被找到,或者没有符合条件的节点(如果图中有环存在)。

    public boolean canFinish(int numCourses, int[][] prerequisites) {        int[][] matrix = new int[numCourses][numCourses]; // i -> j        int[] indegree = new int[numCourses];        for (int i=0; i<prerequisites.length; i++) {            int ready = prerequisites[i][0];            int pre = prerequisites[i][1];            if (matrix[pre][ready] == 0)                indegree[ready]++; //duplicate case            matrix[pre][ready] = 1;        }        int count = 0;        Queue<Integer> queue = new LinkedList();        for (int i=0; i<indegree.length; i++) {            if (indegree[i] == 0) queue.offer(i);        }        while (!queue.isEmpty()) {            int course = queue.poll();            count++;            for (int i=0; i<numCourses; i++) {                if (matrix[course][i] != 0) {                    if (--indegree[i] == 0)                        queue.offer(i);                }            }        }        return count == numCourses;    }
1 0
原创粉丝点击