【算法总结】graph 图的问题

来源:互联网 发布:剑三唱歌捏开脸数据 编辑:程序博客网 时间:2024/05/22 04:06

  1. 描述及例题:
    在一个点线组成的矩阵关系上即为一个图的问题。图的问题主要分为三种类型:
    • Deep copy: 在图上建立一个新的图,把原图的关系都copy到新图上。
      • Clone Graph
      • Copy List with Random Pointer
    • Union find: 在图上找到有几个union块。
      • Surrounded Regions
      • Number of Islands
      • Number of Islands II 
    • Topological sort: 根据pair的关系,或者点线的关系,构建出一个图,找出从start到end的path。
      • Alien Dictionary 
      • Course Schedule
      • Course Schedule II
      • Word Ladder
      • Topological sort
  2. 解决思路及时间复杂度:
    图的问题基本都采用 DFS或者BFS的思路进行解决。
    • Deep copy:
      • 先遍历一遍原图,一边遍历一边建立新的图的点。用hashmap记录原node和新node之间的关系。
      • 再复制边的关系。把原图的边的关系,在新的node之间边的关系同样复制
    • 以Clone Graph为例,代码如下:
      public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {        if(node == null){            return null;        }        // write your code here        ArrayList<UndirectedGraphNode> list = new ArrayList<UndirectedGraphNode>();        HashMap<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<UndirectedGraphNode, UndirectedGraphNode>();        int size = 0;        list.add(node);        UndirectedGraphNode newHead = new UndirectedGraphNode(node.label);        map.put(node, newHead);        while(size<list.size()){            for(UndirectedGraphNode n : list.get(size).neighbors){                if(!map.containsKey(n)){                    UndirectedGraphNode newNode = new UndirectedGraphNode(n.label);                    map.put(n, newNode);                    list.add(n);                }            }           size++;         }        //copy edge        for(int i=0; i<list.size(); i++){             UndirectedGraphNode newN = map.get(list.get(i));             ArrayList<UndirectedGraphNode> newNeighbor = new ArrayList<UndirectedGraphNode>();            for(UndirectedGraphNode neiNode : list.get(i).neighbors){               newNeighbor.add(map.get(neiNode));            }            newN.neighbors = newNeighbor;        }        return newHead;            }


    • Union find:
      • 遍历整个图,一但找到符合条件的点进行dfs,把整个union进行标记,并记录union个数。
    • Number of Islands为例:
      public class Solution {    public int numIslands(boolean[][] grid) {        if(grid == null || grid.length == 0 || grid[0].length == 0){            return 0;        }        int res = 0;        boolean[][] visited = new boolean[grid.length][grid[0].length];        for(int i=0; i<grid.length; i++){            for(int j=0; j<grid[0].length; j++){                if(grid[i][j] && !visited[i][j]){                    dfs(i, j, grid, visited);                    res++;                }            }        }        return res;    }    private void dfs(int i, int j, boolean[][] grid, boolean[][] visited){        //end condition        if(i>=grid.length || i<0 || j>=grid[0].length || j<0 || visited[i][j] || !grid[i][j]){            return;        }        visited[i][j] = true;        dfs(i+1, j, grid, visited);        dfs(i-1, j, grid, visited);        dfs(i, j+1, grid, visited);        dfs(i, j-1, grid, visited);    }}


    • Topological sort:
      • 先用hashMap记录到所有Node的入度,选择入度为0的点为起点。
      • 从起点开始进行bfs,每遍历一个点就入度减一,直到入度为0时,把这个点加入结果顺序中。
      • 注意点:环的问题,如果图是有环的,则计数器会产生断层,即某个节点的计数器永远无法清零(有环意味着有的节点被多加了1,然而遍历的时候一次只减一个1,所以导致无法归零),这样该节点也无法加入到结果中。所以我们只要判断这个结果的节点数和实际图中节点数相等,就代表无环,不相等,则代表有环。
    • Topological sort代码示例:
      public class Solution {    public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {        ArrayList<DirectedGraphNode> res = new ArrayList<DirectedGraphNode>();        if(graph==null || graph.size()==0){            return res;        }        //record indegree        HashMap<DirectedGraphNode, Integer> map = new HashMap<DirectedGraphNode, Integer>();         for(int i=0; i<graph.size(); i++){            DirectedGraphNode node = graph.get(i);            for(DirectedGraphNode n : node.neighbors){                if(map.containsKey(n)){                    map.put(n, map.get(n)+1);                }else{                    map.put(n, 1);                }            }        }        //find start point        LinkedList<DirectedGraphNode> queue = new LinkedList<DirectedGraphNode>();        for(int i=0; i<graph.size(); i++){            if(!map.containsKey(graph.get(i))){                res.add(graph.get(i));                queue.offer(graph.get(i));            }        }        //travelsal        while(!queue.isEmpty()){            DirectedGraphNode node = queue.poll();            for(DirectedGraphNode n : node.neighbors){                if(map.containsKey(n)){                    map.put(n, map.get(n)-1);                    if(map.get(n)==0){                        res.add(n);                        queue.offer(n);                    }                }            }        }        return res;    }}


  3. 代码模板示例:
    主要是用dfs或bfs去解决。所以模板以dfs和bfs的递归和迭代两种实现方式为主。
    • DFS递归:见island那题。注意visited维护。
    • DFS迭代:用stack实现。
    • BFS递归:一般不用递归实现。
    • BFS迭代:用queue实现。

0 0
原创粉丝点击