1.Maximum Depth of Binary Tree
这是道简单的分治习题了
分:
左子树最大深度
右子树最大深度
治:
最大深度等于max(左子树,右子树)+1
public class Solution { public int maxDepth(TreeNode root) { if (root == null) { return 0; } int left = maxDepth(root.left); int right = maxDepth(root.right); return Math.max(left, right) + 1; } }
2.Validate Binary Search Tree
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
- The left subtree of a node contains only nodes with keys less than the node‘s key.
- The right subtree of a node contains only nodes with keys greater than the node‘s key.
- Both the left and right subtrees must also be binary search trees.
该问题运用分治发的分析思路如下:分:判断左子树判断右子树治:仅当左子树是并且右子树是而且 左子树的最大值<root.val<右子树的最小值 递归结束条件就是判断root是否为空了。不用判断叶子节点,因为判断叶子节点也是得先判断根节点然后在判断左节点和右节点是否为空 public class Solution { public boolean isValidBST(TreeNode root) { if(root == null){ return true; } if(root.left==null&&root.right==null){ return true; }else if(root.left==null){ if(isValidBST(root.right)&&root.val<getMin(root.right)) return true; // else return false; }else if(root.right==null){ if(isValidBST(root.left)&&getMax(root.left)<root.val) return true; // else return false; }else{ if(isValidBST(root.left)&&isValidBST(root.right)&& getMax(root.left)<root.val&&root.val<getMin(root.right)) return true; // else return false; } return false; } //root cannot be null public int getMin(TreeNode root){ if(root.left==null) return root.val; return getMin(root.left); } //root cannot be null public int getMax(TreeNode root){ if(root.right==null) return root.val; return getMax(root.right); } }
我的做法在判断为空的问题上太麻烦了,使用了太多的if判断,可以反其道而行之,就好很多。如下,九章的答案 .九章上面还有好几种奇妙的答案可以参考。
/* SOLUTION 3: Use the recursive version2. */ public boolean isValidBST3(TreeNode root) { // Just use the inOrder traversal to solve the problem. if (root == null) { return true; } return dfs(root, Long.MIN_VALUE, Long.MAX_VALUE); } public class ReturnType { int min; int max; boolean isBST; public ReturnType (int min, int max, boolean isBST) { this.min = min; this.max = max; this.isBST = isBST; } } // BST: // 1. Left tree is BST; // 2. Right tree is BST; // 3. root value is bigger than the max value of left tree and // smaller than the min value of the right tree. public ReturnType dfs(TreeNode root) { ReturnType ret = new ReturnType(Integer.MAX_VALUE, Integer.MIN_VALUE, true); if (root == null) { return ret; } ReturnType left = dfs(root.left); ReturnType right = dfs(root.right); // determine the left tree and the right tree; if (!left.isBST || !right.isBST) { ret.isBST = false; return ret; } // 判断Root.left != null是有必要的,如果root.val是MAX 或是MIN value,判断会失误 if (root.left != null && root.val <= left.max) { ret.isBST = false; return ret; } if (root.right != null && root.val >= right.min) { ret.isBST = false; return ret; } return new ReturnType(Math.min(root.val, left.min), Math.max(root.val, right.max), true); }
3
3. Binary Tree Preorder Traversal
很典型的分治做法:
//Version 2: Divide & Conquer public class Solution { public ArrayList<Integer> preorderTraversal(TreeNode root) { ArrayList<Integer> result = new ArrayList<Integer>(); // null or leaf if (root == null) { return result; } // Divide ArrayList<Integer> left = preorderTraversal(root.left); ArrayList<Integer> right = preorderTraversal(root.right); // Conquer result.add(root.val); result.addAll(left); result.addAll(right); return result; } }
当然前序遍历问题还有比较常用的几种解法如下:
使用堆栈的非递归形式:public class Solution { public List<Integer> preorderTraversal(TreeNode root) { Stack<TreeNode> stack = new Stack<TreeNode>(); List<Integer> preorder = new ArrayList<Integer>(); if (root == null) { return preorder; } stack.push(root); while (!stack.empty()) { TreeNode node = stack.pop(); preorder.add(node.val); if (node.right != null) { stack.push(node.right); } if (node.left != null) { stack.push(node.left); } } return preorder; } } //Version 1: Traverse public class Solution { public ArrayList<Integer> preorderTraversal(TreeNode root) { ArrayList<Integer> result = new ArrayList<Integer>(); traverse(root, result); return result; } private void traverse(TreeNode root, ArrayList<Integer> result) { if (root == null) { return; } result.add(root.val); traverse(root.left, result); traverse(root.right, result); } }
和仿后序方法:
public class Solution { public List<Integer> preorderTraversal(TreeNode root) { ArrayList<Integer> result = new ArrayList<Integer>(); if(root == null) return result; Stack<TreeNode> stack = new Stack<TreeNode>(); stack.push(root); TreeNode prev = null; while(!stack.empty()){ TreeNode curr = stack.peek(); if(prev==null||curr==prev.left||curr==prev.right){ result.add(curr.val); if(curr.left!= null){ stack.push(curr.left); }else if(curr.right!=null){ stack.push(curr.right); } else{ stack.pop(); } }else if(prev==curr.left){ if(curr.right!=null){ stack.push(curr.right); } else{ stack.pop(); } }else if(prev==curr.right){ stack.pop(); } prev = curr; } return result; } }
这里是些前序遍历的模板
Template 1: Traverse public class Solution { public void traverse(TreeNode root) { if (root == null) { return; } // do something with root traverse(root.left); // do something with root traverse(root.right); // do something with root } } Tempate 2: Divide & Conquer public class Solution { public ResultType traversal(TreeNode root) { // null or leaf if (root == null) { // do something and return; } // Divide ResultType left = traversal(root.left); ResultType right = traversal(root.right); // Conquer ResultType result = Merge from left and right. return result; } }
23333333333333333333333333分界线333333333333333333333333333333
以下是课堂笔记:
归并排序和快速排序是典型的分治算法。但是稍有不同的是快速排序是先整体有序,后局部有序;而归并排序则是先局部有序,再整体有序。
而且归并排序虽然比较浪费存储空间,需要数组来回复制,但是其是稳定排序;而快速排序则是不稳定的。这部分内容稍后我也会google后更新。
关于时间复杂度的分析,有个树形分析法,待有时间更新,课堂时间太紧没记全。
概率题,待查待更新。
关于Java中Queue的虚类问题,待更新。
还有一些典型的课件上的习题,我也会更新后整理在这里的,这里是我刷题做笔记的地方,当然九章算法上有更详细的答案,我只是会加一些自己的理解,不嫌弃的话可以瞧瞧,嘿嘿,谢谢大家了。
时间: 2024-11-05 15:56:10