8.Tree
1.Maximum Depth of Binary Tree
求最大depth,很簡單:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}
return findDepth(root,1);
}
public int findDepth(TreeNode node,int num){
int left=Integer.MIN_VALUE,right=Integer.MIN_VALUE;
if(node.left==null&&node.right==null){
return num;
}
if(node.left!=null){
left = findDepth(node.left,num+1);
}
if(node.right!=null){
right = findDepth(node.right,num+1);
}
num = Math.max(left,right);
return num;
}
}
關於java位運算符(<<,>>):
1.<<:左移運算符,num << n,相當於num乘以2的n次方,如3<<4=48。
2.>>:右移運算符,num >> n,相當於num除以2的n次方,如32>>4=2。
2.Count Complete Tree Nodes
計算一顆完全二叉樹的nodes數。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
//success 1
//可能timeOut,每次都需要計算height,所以很慢
// class Solution {
// int height(TreeNode root) {
// return root == null ? -1 : 1 + height(root.left);
// }
// public int countNodes(TreeNode root) {
// int h = height(root);
// return h < 0 ? 0 :
// //如果相差1,說明左邊是完全二叉樹,那麼加左半邊
// //如果不相差1,說明左邊不是完全二叉樹,那麼加上上半部分,將root下移。
// height(root.right) == h-1 ? (1 << h) + countNodes(root.right)
// : (1 << h-1) + countNodes(root.left);
// }
// }
//success 2
class Solution {
int height(TreeNode root) {
return root == null ? -1 : 1 + height(root.left);
}
public int countNodes(TreeNode root) {
int nodes = 0, h = height(root);
while (root != null) {
if (height(root.right) == h - 1) {
nodes += 1 << h;
root = root.right;
} else {
nodes += 1 << h-1;
root = root.left;
}
h--;
}
return nodes;
}
}
可參考Concise Java solutions O(log(n)^2)。
3.Serialize and Deserialize BST
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary search tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary search tree can be serialized to a string and this string can be deserialized to the original tree structure.
The encoded string should be as compact as possible.
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root==null){
return "error";
}
List list = preorderTraversal(root);
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
sb.append(",");
}
return sb.toString().substring(0,sb.length()-1);
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if("error".equals(data)){
return null;
}
String[] array = data.split(",");
TreeNode root = new TreeNode(Integer.valueOf(array[0]));
for (int i=1;i<array.length;i++){
TreeNode node = new TreeNode(Integer.valueOf(array[i]));
findPlace(node,root);
}
return root;
}
void findPlace(TreeNode node,TreeNode root){
if(node.val<root.val){
if(root.left==null){
root.left=node;
}else{
findPlace(node,root.left);
}
}else{
if(root.right==null){
root.right=node;
}else{
findPlace(node,root.right);
}
}
}
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
//Stack is a subclass of Vector that implements a standard last-in, first-out stack.
Stack<TreeNode> stack = new Stack<>();
//用stack來記錄right
while(root!=null){
list.add(root.val);
//處理right
if(root.right!=null){
stack.push(root.right);
}
//處理left
root = root.left;
if(root==null&&!stack.isEmpty()){
root = stack.pop();
}
}
return list;
}
}
4.Unique Binary Search Trees
受Count Number of Binary Search Tree Possible given n keys Dynamic Programming的啓發,採用DP的思想來計算。
public class Solution {
public int numTrees(int n) {
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for (int i = 1; i <= n; i++) {
calDpM(dp,i);
}
return dp[n];
}
void calDpM(int[] dp,int m){
int sum=0;
for (int i = 0; i <= m-1; i++) {
sum+=dp[i]*dp[m-1-i];
}
dp[m] = sum;
}
}
5.Binary Tree Inorder Traversal
實現二叉樹的中序遍歷。跟前面2.Binary Tree Preorder Traversal
實現的前序遍歷思路一樣,也是有遞歸和迭代兩種解法(當然,迭代肯定要難一點)。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
//success 1
//recusive method
// public class Solution {
// public List<Integer> inorderTraversal(TreeNode root) {
// List<Integer> list = new ArrayList<>();
// if(root==null){
// return list;
// }
// recursive(list,root);
// return list;
// }
// void recursive(List list,TreeNode node){
// if(node.left!=null){
// recursive(list,node.left);
// }
// list.add(node.val);
// if(node.right!=null){
// recursive(list,node.right);
// }
// }
// }
//success 2
//iterative method
public class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode cur = root;
while(cur!=null || !stack.empty()){
while(cur!=null){
stack.add(cur);
cur = cur.left;
}
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
return list;
}
}
6.Binary Tree Postorder Traversal
有了前面的前序和中序遍歷,我們乘熱打鐵把後序遍歷的兩種方法也實現了吧!
前序遍歷的順序:root-left-right
中序遍歷的順序:left-root-right
後序遍歷的順序:left-right-root
注意到後序遍歷與前序遍歷之間的關係,將前序遍歷中left與right互換,然後將結果reverse就得到了後序(trick)。所以在前序遍歷的基礎上改動:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
//success 1
//recusive method
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root==null){
return list;
}
recursive(list,root);
return list;
}
void recursive(List list,TreeNode node){
if(node.left!=null){
recursive(list,node.left);
}
if(node.right!=null){
recursive(list,node.right);
}
list.add(node.val);
}
}
//success 2
//iterative method
// public class Solution {
// public List<Integer> postorderTraversal(TreeNode root) {
// List<Integer> list = new ArrayList<>();
// //Stack is a subclass of Vector that implements a standard last-in, first-out stack.
// Stack<TreeNode> stack = new Stack<>();
// //用stack來記錄left
// while(root!=null){
// list.add(root.val);
// //處理left
// if(root.left!=null){
// stack.push(root.left);
// }
// //處理right
// root = root.right;
// if(root==null&&!stack.isEmpty()){
// root = stack.pop();
// }
// }
// Collections.reverse(list);
// return list;
// }
// }
關於三種順序的迭代算法總結:Preorder, Inorder, and Postorder Iteratively Summarization。