【算法总结】graph 图的问题

  1. 描述及例题:
    在一个点线组成的矩阵关系上即为一个图的问题。图的问题主要分为三种类型:
  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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值