zoukankan      html  css  js  c++  java
  • [Daily Coding Problem 72] Max path value in directed graph

    This problem was asked by Google.

    In a directed graph, each node is assigned an uppercase letter. We define a path's value as the number of most frequently-occurring letter along that path. For example, if a path in the graph goes through "ABACA", the value of the path is 3, since there are 3 occurrences of 'A' on the path.

    Given a graph with n nodes and m directed edges, return the largest value path of the graph. If the largest value is infinite, then return -1.

    The graph is represented with a string and an edge list. The i-th character represents the uppercase letter of the i-th node. Each tuple in the edge list (i, j) means there is a directed edge from the i-th node to the j-th node. Self-edges are possible, as well as multi-edges.

    For example, the following input graph:

    ABACA
    
    [(0, 1),
     (0, 2),
     (2, 3),
     (3, 4)]
    

    Would have maximum value 3 using the path of vertices [0, 2, 3, 4](A, A, C, A).

    The following input graph:

    A
    
    [(0, 0)]
    

    Should return null, since we have an infinite loop.

    The naive solution would be to try every single path from every vertex, counting up each path's value and keep track of the maximum values we've seen. To do this, we can use DFS to try every path and return INFINITY if we come across a cycle.  However, this would be terribly slow with a runtime of O(V * (V + E)) since we need to perform an O(V + E) DFS V times.

    The reason that the above naive solution is inefficent is because it does not memoize any previously calculated results,  for a path that has just been traversed, it will traverse all of its sub-paths. This sounds like a good problem for dynamic programming.

    Since we're using the alphabet of upper case characters, we have a fixed number 26 of potential values that contribute to the max value path.  Let's keep a matrix of size N by 26 T[i][j]. 

    T[i][j] is the max value that can be made using the ith node as path starting node and jth letter. We must keep all of the path values using all possible letters because a local max path does not necessarily lead to a global max path.  

    T[i][j] = max of T[neighbor][j] for all i's neighbors.  We also need to count the current node too, so increment T[i][current_char] by one, where current_char is the current node's assigned letter. This solution is O(V + E) in runtime as it never visits the same vertex or edge more than once. The space used is O(V + E) for all the information book-keeping.

    The DFS implementation uses a tri-state to avoid visiting the same vertex more than once and detecting cycles.

    public class MaxGraphPath {
        private final int UNVISITED = 0;
        private final int VISITING = 1;
        private final int VISITED = 2;
        public int maxGraphPath(String s, int[][] edges) {
            Map<Integer, List<Integer>> graph = constructGraph(s, edges);
            int[] states = new int[s.length()];
            Arrays.fill(states, UNVISITED);
            int[][] maxPaths = new int[s.length()][26];
    
            for(int node = 0; node < s.length(); node++) {
                if(states[node] == UNVISITED) {
                    if(dfs(s, graph, states, maxPaths, node)) {
                        return -1;
                    }
                }
            }
            int maxPathValue = 0;
            for(int i = 0; i < s.length(); i++) {
                for(int j = 0; j < 26; j++) {
                    maxPathValue = Math.max(maxPaths[i][j], maxPathValue);
                }
            }
            return maxPathValue;
        }
        private Map<Integer, List<Integer>> constructGraph(String s, int[][] edges) {
            Map<Integer, List<Integer>> graph = new HashMap<>();
            for(int i = 0; i < s.length(); i++) {
                graph.put(i, new ArrayList<>());
            }
            for(int i = 0; i < edges.length; i++) {
                graph.get(edges[i][0]).add(edges[i][1]);
            }
            return graph;
        }
        private boolean dfs(String s, Map<Integer, List<Integer>> graph, int[] states, int[][] maxPaths, int node) {
            if(states[node] == VISITED) {
                return false;
            }
            else if(states[node] == VISITING) {
                return true;
            }
            states[node] = VISITING;
            for(int neighbor : graph.get(node)) {
                if(dfs(s, graph, states, maxPaths, neighbor)) {
             return true;
           } }
    for(int neighbor : graph.get(node)) { for(int letter = 0; letter < 26; letter++) { maxPaths[node][letter] = Math.max(maxPaths[node][letter], maxPaths[neighbor][letter]); } } maxPaths[node][s.charAt(node) - 'A']++; states[node] = VISITED; return false; } }

      

    Related Topics

    How do you detect if there is any cycle in directed/undirected graph?

    Core Data Structures, Algorithms and Concepts

    Related Problems

    Parallel Courses

  • 相关阅读:
    24.最优布线问题(kruskal算法)
    24.最优布线问题(kruskal算法)
    Algs4-1.4.11为StaticSETofInts添加一个实列方法howMany()
    Algs4-1.4.9预测程序运行时间
    Algs4-1.4.10二分查找找出元素所在的最小索引
    Algs4-1.4.7统计算术运算与比较次数
    Algs4-1.4.8计算输入文件中相等的整数对的数量
    Algs4-1.4.6给出以下代码段的运行时间的增长数量级
    Algs4- 1.4.4参照表1.4.4为TwoSum建立一和类似的表格
    Algs4-1.4.2修改ThreeSum防止两个int值相加可能溢出
  • 原文地址:https://www.cnblogs.com/lz87/p/10354361.html
Copyright © 2011-2022 走看看