标签:
package DFS; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.Stack; public class RealDFS { public static void main(String[] args) { // TODO Auto-generated method stub } /* * 在进入DFS这个话题前面,首先得讲一下DFS的基本公式和基本概念,那么下面是从网上摘抄的一段关于dfs的比较传统的代码 * Depth-First-Search( MazeCell c ) * If c is the goal * Exit * Else Mark c * "Visit In Progress" * Foreach neighbor n of c If n "Unvisited" * Depth-First-Search( n ) * Mark c "Visited" * End procedure * 也就是说dfs是找到任何相邻的子节点,然后对于每个子节点分别的进入继续dfs */ /* * 257.Binary Tree Paths * 11.21 By mingyang */ public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<String>(); if (root != null) dfs(root, "", res); return res; } private void dfs(TreeNode root, String path, List<String> res) { if (root.left == null && root.right == null) res.add(path + root.val); if (root.left != null) dfs(root.left, path + root.val + "->", res); if (root.right != null) dfs(root.right, path + root.val + "->", res); } /* * 199. Binary Tree Right Side View * 11.21 By Mingyang * 在recursive的算法,就是贴着树的右边界往下面走,如果不行往左边偏一个,然后继续往右边偏,利用末尾的个数与层数相等的技巧 * 其实是一种根右左的算法,很巧妙 */ public List<Integer> rightSideView(TreeNode root) { List<Integer> result = new ArrayList<Integer>(); rightSideView(root, result, 0); return result; } public void rightSideView(TreeNode curr, List<Integer> result, int currDepth){ if(curr == null){ return; } if(currDepth == result.size()){ result.add(curr.val); } rightSideView(curr.right, result, currDepth + 1); rightSideView(curr.left, result, currDepth + 1); } /* * 133. Clone Graph * 3.20 by Mingyang * 这道题目就是典型的dfs了 */ private HashMap<Integer, UndirectedGraphNode> map = new HashMap<Integer, UndirectedGraphNode>(); public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { return dfs(node); } private UndirectedGraphNode dfs(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(dfs(neighbor)); } return clone; } //用stack来实现dfs public UndirectedGraphNode cloneGraph1(UndirectedGraphNode node) { if(node == null) return null; HashMap<UndirectedGraphNode, UndirectedGraphNode> hm = new HashMap<UndirectedGraphNode, UndirectedGraphNode>(); LinkedList<UndirectedGraphNode> stack = new LinkedList<UndirectedGraphNode>(); UndirectedGraphNode head = new UndirectedGraphNode(node.label); hm.put(node, head); stack.push(node); while(!stack.isEmpty()){ UndirectedGraphNode curnode = stack.pop(); for(UndirectedGraphNode aneighbor: curnode.neighbors){//check each neighbor if(!hm.containsKey(aneighbor)){//if not visited,then push to stack stack.push(aneighbor); UndirectedGraphNode newneighbor = new UndirectedGraphNode(aneighbor.label); hm.put(aneighbor, newneighbor); } hm.get(curnode).neighbors.add(hm.get(aneighbor)); } } return head; } /* * 129. Sum Root to Leaf Numbers * 11.23 By Mingyang * dfs包含三种,这里是dfs的preorder方法,先解决根再是左右 */ public int sumNumbers(TreeNode root) { return dfs(root, 0); } public int dfs(TreeNode root, int levelBase) { if (root == null) return 0; if (root.left == null && root.right == null) { return levelBase + root.val; } int nextLevelBase = (levelBase + root.val) * 10; int leftSubTreeSum = dfs(root.left, nextLevelBase); int rightSubTreeSum = dfs(root.right, nextLevelBase); return leftSubTreeSum + rightSubTreeSum; } /* * 337. House Robber III * 2016-3-14 by Mingyang * 刚开始看这道题目有一点误区,以为是奇数排和偶数排之和比较大写,然后选出更大的,所以自己就写了BFS的代码,但发现如下的case不过: * 4 * 1 * 2 *3 *因为这里面的最大的其实是4和3,中间隔了两行不偷,所以我觉得这道题目是dp加上dfs,两个线路的dfs的最大加起来。 *dfs all the nodes of the tree, each node return two number, int[] num, *num[0] is the max value while rob this node, *num[1] is max value while not rob this value. *Current node return value only depend on its children‘s value */ public int rob(TreeNode root) { int[] num = dfs(root); return Math.max(num[0], num[1]); } private int[] dfs(TreeNode x) { if (x == null) return new int[2]; int[] left = dfs(x.left); int[] right = dfs(x.right); int[] res = new int[2]; res[0] = left[1] + right[1] + x.val; res[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]); return res; } /* * 332. Reconstruct Itinerary * 2016-3-14 by Mingyang * 这道题给我们一堆飞机票,让我们建立一个行程单,如果有多种方法,取其中字母顺序小的那种方法。 * 这道题的本质是有向图的遍历问题,那么LeetCode关于有向图的题只有两道Course Schedule和Course Schedule II, * 而那两道是关于有向图的顶点的遍历的,而本题是关于有向图的边的遍历。 * 每张机票都是有向图的一条边,我们需要找出一条经过所有边的路径,那么DFS不是我们的不二选择。 * 代码前半段都在准备工作。把所有的tickets全部装进一个map,string对应了一个priority queue * 后半段dfs中,找出第一个顺序的结果。最终输出是从最后一个开始,一个一个往前退的情况下addFirst加起来的 */ Map<String, PriorityQueue<String>> flights; LinkedList<String> path; public List<String> findItinerary(String[][] tickets) { flights = new HashMap<String, PriorityQueue<String>>(); path = new LinkedList<String>(); for (String[] ticket : tickets) { if(!flights.containsKey(ticket[0])){ flights.put(ticket[0], new PriorityQueue<String>()); } flights.get(ticket[0]).add(ticket[1]); } dfs("JFK"); return path; } public void dfs(String departure) { PriorityQueue<String> arrivals = flights.get(departure); while (arrivals != null && !arrivals.isEmpty()) dfs(arrivals.poll()); path.addFirst(departure); } /* * 329. Longest Increasing Path in a Matrix * 2016-3-14 by Mingyang */ int []dx = { 1 , -1, 0 , 0 }; int []dy = { 0 , 0 , 1 , -1 }; public int longestIncreasingPath(int[][] matrix) { if (matrix.length == 0) return 0; int m = matrix.length, n = matrix[0].length; int[][] dis = new int [m][n]; int ans = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { ans = Math.max(ans, dfs( i, j, m, n, matrix, dis)); } } return ans; } public int dfs(int x, int y, int m,int n,int[][] matrix, int[][] dis) { if (dis[x][y] != 0) return dis[x][y]; for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; if (nx >= 0 && ny >= 0 && nx < m && ny < n && matrix[nx][ny] > matrix[x][y]) { dis[x][y] = Math.max(dis[x][y], dfs(nx, ny, m, n, matrix, dis)); } } return ++dis[x][y]; } /* * 323 Number of Connected Components in an Undirected Graph * 2016-3-14 by Mingyang * Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), * write a function to find the number of connected components in an undirected graph. * Note:You can assume that no duplicate edges will appear in edges. * Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges. */ public int countComponents(int n, int[][] edges) { if (n <= 0 || edges == null) { return 0;} if (n == 1 && edges.length == 0) { return 1;} int result = 0; boolean[] visited = new boolean[n]; // step 1: create the adj list from edge list List[] adjList = new List[n]; for (int i = 0; i < n; i++) { adjList[i] = new ArrayList<Integer>(); } for (int[] edge : edges) { int from = edge[0]; int to = edge[1]; adjList[from].add(to); adjList[to].add(from);} // step 2: calculate the number of cc for (int i = 0; i < n; i++) { if (!visited[i]) { result++; countCCHelper(i, adjList, visited);}} return result;} private void countCCHelper(int node, List[] adjList, boolean[] visited) { if (visited[node]) {return;} visited[node] = true; List<Integer> neighbors = adjList[node]; for (int neighbor : neighbors) { countCCHelper(neighbor, adjList, visited);}} /* * 301. Remove Invalid Parentheses * 2016-3-14 by Mingyang * https://leetcode.com/discuss/72208/easiest-9ms-java-solution * 括号总是成对出现的,因此我们只需要记录尚未匹配的(。 * 每次循环时有如下三种情况: * (, 保留或者不保留。 * ), 如果我们有未匹配的(,则有两种选择;否则,只能不保留。 * 保留其他字符。 * 因为我们要移除数量最少的括号,我们应该得到最大的匹配()数量,注意下面两行的顺序。 * dfs(str.substring(1), subRes + ‘(‘, countLeft + 1, maxLeft + 1); * dfs(str.substring(1), subRes, countLeft, maxLeft); * 它可以保证最长的结果出现在比它较短的结果前面。 */ private List<String> res = new ArrayList<String>(); private int max = 0; public List<String> removeInvalidParentheses(String s) { dfs(s, "", 0, 0); if (res.size() == 0) { res.add(""); } return res; } private void dfs(String str, String subRes, int countLeft, int maxLeft) { if (str.length() == 0) { if (countLeft == 0 && subRes.length() != 0) { if (maxLeft > max) { max = maxLeft; } if (max == maxLeft && !res.contains(subRes)) { res.add(subRes.toString()); } } return; } if (str.charAt(0) == ‘(‘) { dfs(str.substring(1), subRes.concat("("), countLeft + 1,maxLeft + 1); dfs(str.substring(1), subRes, countLeft, maxLeft); } else if (str.charAt(0) == ‘)‘) { if (countLeft > 0) { dfs(str.substring(1), subRes.concat(")"), countLeft - 1,maxLeft); } dfs(str.substring(1), subRes, countLeft, maxLeft); } else { dfs(str.substring(1), subRes.concat(String.valueOf(str.charAt(0))),countLeft, maxLeft); } } /* * 98. Validate Binary Search Tree * 11.23 By Mingyang * 这个题目开始用dfs的循环做时,我第一次把root的null的判断写在主函数里面,殊不知这么仅仅判断了root,对于 * 子分支并没有做判断。另外需要注意的是用long不用int,否则会溢出。 * 另外一种方法就是Tree里面的中序遍历。dfs用stack实现 */ public boolean isValidBST(TreeNode root) { return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE); } public boolean isValidBST(TreeNode root, long minVal, long maxVal) { if (root == null) return true; if (root.val >= maxVal || root.val <= minVal) return false; return isValidBST(root.left, minVal, root.val) && isValidBST(root.right, root.val, maxVal); } public boolean isValidBST1(TreeNode root) { Stack<TreeNode> stack = new Stack<TreeNode>(); TreeNode cur = root; TreeNode pre = null; while (!stack.isEmpty() || cur != null) { if (cur != null) { stack.push(cur); cur = cur.left; } else { TreeNode p = stack.pop(); if (pre != null && p.val <= pre.val) { return false; } pre = p; cur = p.right; } } return true; } /* * 99. Recover Binary Search Tree * 11.23 By Mingyang * inorder */ TreeNode pre; TreeNode first; TreeNode second; public void inorder(TreeNode root) { if (root == null) return; inorder(root.left); if (pre == null) {// 只有一种情况,就是最初的情况,最开始的最左边的值-----convert BST to double // linked list pre = root; // pre指针初始 } else { if (pre.val > root.val) { if (first == null) { first = pre;// 第一个逆序点 } second = root; // 不断寻找最后一个逆序点 } pre = root; // pre指针每次后移一位 } inorder(root.right); } public void recoverTree(TreeNode root) { pre = null; first = null; second = null; inorder(root); if (first != null && second != null) { int tmp = first.val; first.val = second.val; second.val = tmp; } } public void recoverTree1(TreeNode root) { // use inorder traversal to detect incorrect node inOrder(root); int temp = first.val; first.val = second.val; second.val = temp; } TreeNode prev = null; TreeNode first1 = null; TreeNode second1 = null; public void inOrder(TreeNode root) { if (root == null) return; // search left tree inOrder(root.left); // in inorder traversal of BST, prev should always have smaller value // than current value if (prev != null && prev.val >= root.val) { // incorrect smaller node is always found as prev node if (first1 == null) first = prev; // incorrect larger node is always found as curr(root) node second1 = root; } // update prev node prev = root; // search right tree inOrder(root.right); } /* * 100 Same Tree * 2016-3-14 by Mingyang */ public boolean isSameTree(TreeNode p, TreeNode q) { if(p == null && q == null) return true; if(p == null || q == null) return false; if(p.val == q.val) return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); return false; } /* * 101. Symmetric Tree * 11.23 By Mingyang */ public boolean isSymmetric(TreeNode root) { if (root == null) return true; return isSymmetricTree(root.left, root.right); } public boolean isSymmetricTree(TreeNode p, TreeNode q) { if (p == null && q == null) return true; if (p == null || q == null) return false; return (p.val == q.val) && isSymmetricTree(p.left, q.right)&& isSymmetricTree(p.right, q.left); } /* * 104. Maximum Depth of Binary Tree * 11.19 By Mingyang * 同样可以用queue,注意!queue不能用null来判决,queue应该用size()来判断的 */ public int maxDepth(TreeNode root) { if (root == null) return 0; return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; } /* * 105. Construct Binary Tree from Preorder and Inorder Traversal * 11.21 By Mingyang * Becuase k is not the length, it it need to -(inStart+1) to get the length */ public TreeNode buildTree2(int[] inorder, int[] postorder) { int inStart = 0; int inEnd = inorder.length - 1; int postStart = 0; int postEnd = postorder.length - 1; return buildTree2(inorder, inStart, inEnd, postorder, postStart,postEnd); } public TreeNode buildTree2(int[] inorder, int inStart, int inEnd,int[] postorder, int postStart, int postEnd) { if (inStart > inEnd || postStart > postEnd) return null; int rootValue = postorder[postEnd]; TreeNode root = new TreeNode(rootValue); int k = 0; for (int i = 0; i < inorder.length; i++) { if (inorder[i] == rootValue) { k = i; break; } } root.left = buildTree2(inorder, inStart, k - 1, postorder, postStart, postStart + k - (inStart + 1)); // Becuase k is not the length, it it need to -(inStart+1) to get the length root.right = buildTree2(inorder, k + 1, inEnd, postorder, postStart + k - inStart, postEnd - 1); // postStart+k-inStart = postStart+k-(inStart+1) +1 return root; } /* * 106. Construct Binary Tree from Inorder and preorder Traversal * 11.20 By Mingyang * 千万不要以为root一定在中间那个点,还是要找一下中间点的位置 */ public TreeNode buildTree(int[] preorder, int[] inorder) { int preEnd = preorder.length - 1; int inEnd = inorder.length - 1; return construct(preorder, 0, preEnd, inorder, 0, inEnd); } public TreeNode construct(int[] preorder, int preStart, int preEnd,int[] inorder, int inStart, int inEnd) { if (preStart > preEnd || inStart > inEnd) { return null; } int val = preorder[preStart]; TreeNode p = new TreeNode(val); // find parent element index from inorder int k = 0; for (int i = 0; i < inorder.length; i++) { if (val == inorder[i]) { k = i; break; } } p.left = construct(preorder, preStart + 1, preStart + (k - inStart),inorder, inStart, k - 1); p.right = construct(preorder, preStart + (k - inStart) + 1, preEnd,inorder, k + 1, inEnd); return p; } /* * 108. Convert Sorted Array to Binary Search Tree * 11.20 By Mingyang */ public TreeNode sortedArrayToBST(int[] num) { if (num.length == 0) return null; return sortedArrayToBST(num, 0, num.length - 1); } public TreeNode sortedArrayToBST(int[] num, int start, int end) { if (start > end) return null; int mid = (start + end) / 2; TreeNode root = new TreeNode(num[mid]); root.left = sortedArrayToBST(num, start, mid - 1); root.right = sortedArrayToBST(num, mid + 1, end); return root; } /* * 109.Convert sorted list to BST * 2016.12.24 by Mingyang * 这里的问题是对于一个链表我们是不能常量时间访问它的中间元素的。 * 这时候就要利用到树的中序遍历了,按照递归中序遍历的顺序对链表结点一个个进行访问,而我们要构造的二分查找树正是按照链表的顺序来的。 * 思路就是先对左子树进行递归 * 然后将当前结点作为根,迭代到下一个链表结点,最后在递归求出右子树即可。整体过程就是一次中序遍历,时间复杂度是O(n),空间复杂度是栈空间O(logn) * 但是我没用上面的二分查找,用的是快慢节点recursive来做,所以这么做就有缺陷: */ public TreeNode sortedListToBST(ListNode head) { if(head == null) return null; ListNode fast = head; ListNode slow = head; ListNode prev =null; while(fast != null && fast.next != null) { fast = fast.next.next; prev =slow; slow=slow.next; } TreeNode root = new TreeNode(slow.val); if(prev != null) prev.next = null; else head = null; root.left = sortedListToBST(head); root.right = sortedListToBST(slow.next); return root; } /* * 上面做法的缺陷在哪呢,就在于这个函数的复杂度是n的logn次方,因为,T(n)=n+2T(n/2),这里多就多了这个n * 也就是我们fast从头到尾的遍历的这个时间复杂度。那么每个Subproblem里面就会有n个至少,那么一共有logn个问题 * 因为树的遍历一般的分层就是nlogn。那么下面的问题复杂度就是n,因为只有主函数用了n,每个子函数也只是n,why? * T(n)=2T(n/2)这里每个子函数都是原来复杂度的一半。所以一共就是n的复杂度 * 这个就跟merge sort不一样了,因为merge sort合起来的那个部分需要logn,所以总的就是nlogn * 那么这里为什么是dfs呢?这里的start到end,他的临边就是一个是从start到mid-1,一个是mid这个点,一个是mid+1到end */ private ListNode node; public TreeNode sortedListToBST2(ListNode head) { if(head == null){ return null; } int size = 0; ListNode runner = head; node = head; while(runner != null){ runner = runner.next; size ++; } return inorderHelper(0, size - 1); } public TreeNode inorderHelper(int start, int end){ if(start > end){ return null; } int mid = start + (end - start) / 2; TreeNode left = inorderHelper(start, mid - 1); TreeNode treenode = new TreeNode(node.val); treenode.left = left; node = node.next;//第一次访问到这就是左边已经到头了,才会访问到node节点 TreeNode right = inorderHelper(mid + 1, end); treenode.right = right; return treenode; } /* * 110. Balanced Binary Tree * 1.18 by Mingyang * This improved algorithm works by checking the height of each subtree as we recurse * down from the root. On each node, we recursively get the heights of the left and right * subtrees through the checkHeight method. If the subtree is balanced, then check- * Height will return the actual height of the subtree. If the subtree is not balanced, then * checkHeight will return -1. We will immediately break and return -1 from the current call. */ public boolean isBalanced(TreeNode root) { if (root == null) return true; if (Math.abs(depth(root.left) - depth(root.right)) > 1) return false; return isBalanced(root.left) && isBalanced(root.right); } private int depth(TreeNode root) { if (root == null) return 0; return Math.max(depth(root.left), depth(root.right)) + 1; } /* * 111. Minimum Depth of Binary Tree * 11.18 by Mingyang 还是用queue来做 */ public int minDepth(TreeNode root) { if (root == null) return 0; int left = minDepth(root.left); int right = minDepth(root.right); return (left == 0 || right == 0) ? left + right + 1 : Math.min(left,right) + 1; } /* * 112. Path Sum * 11.18 by Mingyang */ public boolean hasPathSumRec(TreeNode root, int sum) { if (root == null) return false; if (root.left == null && root.right == null && sum - root.val == 0) return true; return hasPathSumRec(root.left, sum - root.val)|| hasPathSumRec(root.right, sum - root.val); } /* * 114. Flatten Binary Tree to Linked List * 11.20 By Mingyang * 注意stack不能用!=null来描述,应该用 * (!stack.isEmpty())来表述!这道题目你会发现好像是根左右的顺序,然后就用stack来写 * 就是一个preorder的变体,在recursive的方法中呢,我们必须用一个全局变量来保存上一个节点的位置,因为 * 我们退回来的时候才可以知道lastNode具体的地方。 */ public void flatten(TreeNode root) { if (root == null) return; Stack<TreeNode> stack = new Stack<TreeNode>(); stack.push(root); TreeNode prev = null; while (!stack.isEmpty()) { TreeNode temp = stack.pop(); if (temp.right != null) stack.push(temp.right); if (temp.left != null) stack.push(temp.left); if (prev != null) { prev.right = temp; prev.left = null; } prev = temp; } } private TreeNode lastNode = null;//lastNode就是连接左边和右边的纽带 public void flattenRec(TreeNode root) { if (root == null) { return; } if (lastNode != null) { lastNode.left = null;//这里面就是真正的改变整个TreeNode的部分,相当于preorder的根操作。 lastNode.right = root; } lastNode = root; TreeNode right = root.right;//这不不能省去,因为一旦省去了以后我们就不能记录当时的root.right了 flatten(root.left); flatten(right); } /* * 116. Populating Next Right Pointers in Each Node * 1.20 By Mingyang *在这里面,因为是满的二叉树,所以所有点都有值,那么root的左边和右边都有值 *我本来想用上面的思路,在外面建立一个father node,然后在子层考虑father和next的关系,但是那么做太复杂了 */ public void connect(TreeLinkNode root) { if(root == null) return; if(root.left != null){//表明不是叶子节点那一行 root.left.next = root.right; if(root.next != null) root.right.next = root.next.left; } connect(root.left); connect(root.right); } /* * 117. Populating Next Right Pointers in Each Node II * 1.20 by Mingyang * 唯一的不同是每次要先找到一个第一个有效的next链接节点,并且递归的时候要先处理右子树,再处理左子树。 */ public void connect1Rec(TreeLinkNode root) { if (root == null) return; TreeLinkNode p = root.next; while (p != null) { if (p.left != null) { p = p.left; break; } if (p.right != null) { p = p.right; break; } p = p.next; } if (root.right != null) { root.right.next = p; } if (root.left != null) { root.left.next = root.right != null ? root.right : p; } connect1Rec(root.right); connect1Rec(root.left); } /* * 124. Binary Tree Maximum Path Sum * 11.21 By Mingyang 刚开始想只用一个int * max来传参,但是后面发现无论怎么改,return的max都要被附上初值 * 所以我们这里出了一个全局变量,这里的任何一个path都要经过一个最高的点,那么这个最高的点就在 * root里面的node,那么每次都是最大的值更新。所以node表示一定经过的。 * 那么返回的整数就是如果最大的path还要通往父节点能提供的最大值。也就是我能提供给父节点一个接口, * 并且最大的值。 */ int maxValue; public int maxPathSum(TreeNode root) { maxValue = Integer.MIN_VALUE; maxPathDown(root); return maxValue; } private int maxPathDown(TreeNode node) { if (node == null) return 0; int left = Math.max(0, maxPathDown(node.left)); int right = Math.max(0, maxPathDown(node.right)); maxValue = Math.max(maxValue, left + right + node.val); return Math.max(left, right) + node.val; } //那你说我不用全局变量,那就只能用数组: public int maxPathSum1(TreeNode root) { int[] max = new int[1]; max[0] = Integer.MIN_VALUE; maxPathSum1(max, root); return max[0]; } private int maxPathSum1(int[] max, TreeNode root){ if(root == null) return 0; int leftMax = Math.max(0, maxPathSum1(max, root.left)); int rightMax = Math.max(0, maxPathSum1(max, root.right)); max[0] = Math.max(max[0], root.val+leftMax+rightMax); return root.val+Math.max(leftMax,rightMax); } } class TreeNode { public int val; public TreeNode left; public TreeNode right; public TreeNode(int x) { val = x; } } class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } class TreeLinkNode { int val; TreeLinkNode left, right, next; TreeLinkNode(int x) { val = x; } } class UndirectedGraphNode { int label; List<UndirectedGraphNode> neighbors; UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); } }
标签:
原文地址:http://www.cnblogs.com/zmyvszk/p/5300945.html