用处:
树是图的特殊状态
图的遍历 Traversal in Graph
• 层级遍历 Level Order Traversal
• 由点及面 Connected Component
• 拓扑排序 Topological Sorting
最短路径 Shortest Path in Simple Graph
• 仅限简单图求最短路径
• 即,图中每条边长度都是1,且没有方向
用queue去存每一层,queue的实现LinkedList<>或ArrayDeque,不能是ArrayList会浪费时间
queue.offer() 加入队列,queue.poll()删除并取出first元素,不用add和pop异常处理不同。
DFS:模板
一、二叉树上的bfs
1、Binary Tree Level Order Traversal : 树的层级遍历 http://www.lintcode.com/problem/binary-tree-level-order-traversal/
not ac :queue.isEmpty() 写错,results 写错,level.add加节点值
Deque LinkedList<>
public class Solution { /** * @param root: The root of binary tree. * @return: Level order a list of lists of integer */ public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) { // write your code here ArrayList<ArrayList<Integer>> results = new ArrayList<>(); if (root == null) { return results; } Deque<TreeNode> queue = new LinkedList<TreeNode>(); queue.offer(root); while(!queue.isEmpty()) { ArrayList<Integer> level = new ArrayList<>(); int size = queue.size(); for (int i = 0; i < size; i++) { TreeNode head = queue.poll(); level.add(head.val); if (head.left != null) { queue.offer(head.left); } if (head.right != null) { queue.offer(head.right); } } results.add(level); } return results; } }
2、序列化: 将“内存”中结构化的数据变成“字符串”的过程 序列化:object to string 反序列化:string to object
什么时候需要序列话:
1. 将内存中的数据持久化存储时 内存中重要的数据不能只是呆在内存里,这样断电就没有了,所需需要用一种方式写入硬盘,在需要的 时候,能否再从硬盘中读出来在内存中重新创建
2. 网络传输时 机器与机器之间交换数据的时候,不可能互相去读对方的内存。只能讲数据变成字符流数据(字符串)后 通过网络传输过去。接受的一方再将字符串解析后到内存中。
常用的一些序列化手段: • XML • Json • Thrift (by Facebook) • ProtoBuf (by Google)
3、序列化算法设计考虑:
• 压缩率。对于网络传输和磁盘存储而言,当然希望更节省。 • 如 Thrift, ProtoBuf 都是为了更快的传输数据和节省存储空间而设计的。
• 可读性。我们希望开发人员,能够通过序列化后的数据直接看懂原始数据是什么。 • 如 Json,LintCode 的输入数据
4、二叉树序列话
任何法进行序列化,只要保证能够解析回来即可。
LintCode 采用的是 BFS 的方式对二叉树数据进行序列化,这样的好处是,你可以更为容易的自己画出 整棵二叉树。
1) http://www.lintcode.com/en/problem/binary-tree-serialization/
class Solution { /** * This method will be invoked first, you should design your own algorithm * to serialize a binary tree which denote by a root node to a string which * can be easily deserialized by your own "deserialize" method later. */ public String serialize(TreeNode root) { // write your code here if (root == null) { return "{}"; } ArrayList<TreeNode> queue = new ArrayList<TreeNode>(); queue.add(root); for (int i = 0; i < queue.size(); i++) { TreeNode node = queue.get(i); if (node == null) { continue; } queue.add(node.left); queue.add(node.right); } while (queue.get(queue.size() - 1) == null) { queue.remove(queue.size() - 1); } StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append(queue.get(0).val); for (int i = 1; i < queue.size(); i++) { if (queue.get(i) == null) { sb.append(",#"); } else { sb.append(","); sb.append(queue.get(i).val); } } sb.append("}"); return sb.toString(); } /** * This method will be invoked second, the argument data is what exactly * you serialized at method "serialize", that means the data is not given by * system, it's given by your own serialize method. So the format of data is * designed by yourself, and deserialize it here as you serialize it in * "serialize" method. */ public TreeNode deserialize(String data) { // write your code here if (data.equals("{}")) { return null; } String[] vals = data.substring(1,data.length() - 1).split(","); ArrayList<TreeNode> queue = new ArrayList<TreeNode>(); TreeNode root = new TreeNode(Integer.parseInt(vals[0])); queue.add(root); int index = 0; boolean isLeft = true; for (int i = 1; i < vals.length; i++) { if (!vals[i].equals("#")) { TreeNode node = new TreeNode(Integer.parseInt(vals[i])); if (isLeft) { queue.get(index).left = node; } else { queue.get(index).right = node; } queue.add(node); } if (!isLeft) { index++; } isLeft = !isLeft; } return root; } }
5、图的序列化
如何表示图的邻接表:Map<Integer, Set<Integer>> 点 -- 和该点相邻的节点
如何判断图是树:1、边比点数少1
2、判断连通性:是否有一个点没和任何点相连,从一点能访问任何一点
1)Graph Valid Tree http://www.lintcode.com/problem/graph-valid-tree/
思路: 判断条件1
初始化图:表示邻接表
判断条件2
public boolean validTree(int n, int[][] edges) { // Write your code here //判断条件1:边和点数 if (n == 0) { return false; } if (edges.length != n - 1) { return false; } //初始化 Map<Integer, Set<Integer>> graph = initializeGraph(n, edges); //判断条件2:连通性 Deque<Integer> queue = new LinkedList<Integer>(); HashSet<Integer> hash = new HashSet<>(); queue.offer(0); hash.add(0); while (!queue.isEmpty()) { int node = queue.poll(); for (Integer neighour : graph.get(node)) { if (hash.contains(neighour)) { continue; } hash.add(neighour); queue.offer(neighour); } } return hash.size() == n; } public Map<Integer, Set<Integer>> initializeGraph(int n, int[][] edges) { Map<Integer, Set<Integer>> graph = new HashMap<>(); for (int i = 0; i < n; i++) { graph.put(i, new HashSet<Integer>()); } for (int i = 0; i < edges.length; i++) { int u = edges[i][0]; int v = edges[i][1]; graph.get(u).add(v); graph.get(v).add(u); } return graph; } }
2)Clone Graph (F) http://www.lintcode.com/problem/clone-graph/ 克隆无相图
***3步
1、得到所有的点 ArrayList<节点> nodes =
bfs: queue 和 hashmap
2、克隆点,old -> new映射关系
3、克隆边
记得对空检查
public class Solution { /** * @param node: A undirected graph node * @return: A undirected graph node */ public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { // write your code here // 1.use bfs algorithm to traverse the graph and get all nodes. if (node == null) { return node; } ArrayList<UndirectedGraphNode> nodes = getNodes(node); //2. copy nodes, store the old->new mapping information in a hash map HashMap<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<>(); for (UndirectedGraphNode n : nodes) { map.put(n, new UndirectedGraphNode (n.label)); } //3.copy neighbors(edges) for (UndirectedGraphNode n : nodes) { UndirectedGraphNode newNode = map.get(n); for (UndirectedGraphNode neighbor : n.neighbors) { UndirectedGraphNode newNeighbor = map.get(neighbor); newNode.neighbors.add(newNeighbor); } } return map.get(node); } private ArrayList<UndirectedGraphNode> getNodes(UndirectedGraphNode node) { Deque<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>(); HashSet<UndirectedGraphNode> set = new HashSet<>(); queue.offer(node); set.add(node); while (!queue.isEmpty()) { UndirectedGraphNode head = queue.poll(); for (UndirectedGraphNode neighbor : head.neighbors) { if (!set.contains(neighbor)) { set.add(neighbor); queue.offer(neighbor); } } } return new ArrayList<UndirectedGraphNode>(set); } }
3)Topological Sorting http://www.lintcode.com/problem/topological-sorting/ 拓扑排序
**1找根节点:没有指向它的节点---用hashmap<邻居节点,该邻接节点被指向的个数>,根节点没存在这个map里
2.将该节点加入结果,依次从此节点开始访问
public class Solution { /** * @param graph: A list of Directed graph node * @return: Any topological order for the given graph. */ public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) { // write your code here ArrayList<DirectedGraphNode> results = new ArrayList<>(); HashMap<DirectedGraphNode,Integer> map = new HashMap<>(); //用map记录 所有 被指向的节点 和 被指向的次数 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); } } } Deque<DirectedGraphNode> queue = new LinkedList<DirectedGraphNode>(); //找到未被指向的根节点,用queue记录根节点,并把该节点加入results for (DirectedGraphNode node : graph) { if (!map.containsKey(node)) { queue.offer(node); results.add(node); } } //从根节点遍历 while (!queue.isEmpty()) { DirectedGraphNode node = queue.poll(); for (DirectedGraphNode n : node.neighbors) { map.put(n,map.get(n) - 1); if (map.get(n) == 0) { results.add(n); queue.offer(n); } } } return results; } }
***矩阵和图的对比
图 Graph N个点,M条边 M最大是 O(N^2) 的级别
图上BFS时间复杂度 = O(M) 所以最坏情况可能是 O(N^2)
矩阵 Matrix N行M列 N*M个点,N*M*2 条边(每个点上下左右4条边,每条边被2个点共享)。
矩阵中BFS时间复杂度 = O(N * M)
6、矩阵中的BFS