树
public class Tree {
private Node root;
public Tree() {
root = null;
}
public Node getRoot() {
return root;
}
//把LeetCode题目用例的数组生成树
public Node initTree(Integer[] nodes) {
//广度优先遍历
Queue<Node> queue = new LinkedList<>();
int level = 0;
queue.add(root = new Node(nodes[0]));
while(!queue.isEmpty()) {
level++;
int len = queue.size();
for (int i = 0; i < len; i++) {
Node node = queue.poll();
//转换成数组对应下标
int index = (int)Math.pow(2,level) - 1 + 2 * i;
//判断越界
if(index > nodes.length - 1) return root;
Integer left = nodes[index];
//生成左子树
if(left == null) node.left = null;
else queue.add(node.left = new Node(left));
//同上
if(index + 1 > nodes.length -1) return root;
Integer right = nodes[index+1];
if(right == null) node.right = null;
else queue.add(node.right = new Node(right));
}
}
return root;
}
//先序遍历递归
public void preOrder(Node root) {
System.out.println(root.data + " ");
preOrder(root.left);
preOrder(root.right);
}
//先序遍历非递归
public void preOrder() {
Stack<Node> stack = new Stack<Node>();
Node node = root;
while(!stack.isEmpty() || node != null) {
if(node != null) {
stack.add(node);
System.out.print(node.data + " ");
node = node.left;
} else {
node = stack.pop();
node = node.right;
}
}
}
//中序遍历递归
public void inOrder(Node root) {
inOrder(root.left);
System.out.print(root.data + " ");
inOrder(root.right);
}
//中序遍历非递归
public void inOrder() {
Stack<Node> stack = new Stack<Node>();
Node node = root;
while(!stack.isEmpty() || node != null) {
if(node != null) {
stack.push(node);
node = node.left;
} else {
node = stack.pop();
System.out.print(node.data + " ");
node = node.right;
}
}
}
//后序遍历递归
public void postOrder(Node localRoot) {
postOrder(localRoot.left);
postOrder(localRoot.right);
System.out.print(localRoot.data + " ");
}
//后序遍历非递归
public void postOrder() {
Stack<Node> s = new Stack<Node>();
Node current; //当前结点
Node pre = null; //前一次访问的结点
s.push(this.root);
while(!s.isEmpty()) {
current = s.peek();
if((current.left == null && current.right == null) ||
(pre != null && ( pre == current.left || pre == current.right))) {
System.out.print(current.data + " "); //如果当前结点没有孩子结点或者孩子节点都已被访问过
s.pop();
pre = current;
} else {
if(null != current.right) s.push(current.right);
if(null != current.left) s.push(current.left);
}
}
}
//层序遍历
public List<List<Integer>> BinaryTreeLevelOrderTraversal(Node root) {
if(root == null) return new ArrayList<>();
Queue<Node> queue = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
queue.add(root);
while(!queue.isEmpty()) {
int count = queue.size();
List<Integer> list = new ArrayList<>();
while(count > 0){
Node node = queue.poll();
list.add(node.data);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
count--;
}
result.add(list);
}
return result;
}
//根据后序遍历和中序遍历生成树
public void initTree(int[] preOrder,int[] inOrder) {
this.root = this.initTree(preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1);
}
public Node initTree(int[] preOrder,int start1,int end1,int[] inOrder,int start2,int end2) {
if(start1 > end1 || start2 > end2) return null;
int rootData = preOrder[start1];
Node head = new Node(rootData);
int rootIndex = findIndexInArray(inOrder,rootData,start2,end2);
int offSet = rootIndex - start2 -1;
Node left = initTree(preOrder,start1+1,start1+1+offSet,inOrder,start2,start2+offSet);
Node right = initTree(preOrder,start1+offSet+2,end1,inOrder,rootIndex+1,end2);
head.left = left;
head.right = right;
return head;
}
public int findIndexInArray(int[] a,int x,int begin,int end) {
for (int i = begin; i <= end; i++) {
if(a[i] == x) return i;
}
return -1;
}
public void minDepth(Node root) {
//见 Minimum Depth of Binary Tree 类
}
public void maxDepth(Node root) {
//见 Maximum Depth of Binary Tree 类
}
}
验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
解:
方法1.中序遍历 查看当前节点是否大于前继节点(是否是升序)
方法2.递归,判断左子树最大值小于根节点,右子树最小值大于根节点
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
double last = -Double.MAX_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
if (isValidBST(root.left)) {
if (last < root.val) {
last = root.val;
return isValidBST(root.right);
}
}
return false;
}
}
二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。
解:
方法1.若数据结构中存在父节点,公共祖先转化成求第一个相交节点 见Intersection_of_Two_Linked_Lists
方法2.递归左右子树 找到p或者q则返回 若一个节点左右子树都含p或q 那么那个节点就是公共祖先
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
//WRONG:return left == null ? right : right == null ? null : root;
return left != null && right != null ? root : left != null ? left : right;
}
}
二叉树的层次遍历
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
解:
方法1:BFS Queue
方法2:DFS 直接放入到对应层次的数组中
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null) return new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
queue.add(root);
while(!queue.isEmpty()) {
int count = queue.size();
List<Integer> list = new ArrayList<>();
while(count > 0){
TreeNode node = queue.poll();
list.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
count--;
}
result.add(list);
}
return result;
}
}
二叉树的最大深度
给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
解:
方法1.递归 计算左节点深度和右节点深度
方法2.BFS 判断是否是叶子节点
方法3.DFS 更新层数和min
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
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;
}
}
或
public int maxDepth(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int level = 0;
while(!queue.isEmpty()) {
level++;
int count = queue.size();
while(count > 0){
TreeNode node = queue.poll();
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
count--;
}
}
return level;
}
二叉树的最小深度
给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最小深度 2.
解:
方法1.递归 计算左节点深度和右节点深度
方法2.BFS 判断是否是叶子节点
方法3.DFS 更新层数和min
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int minDepth(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int level = 1;
while(!queue.isEmpty()) {
int count = queue.size();
while(count > 0){
TreeNode node = queue.poll();
if(node.left == null && node.right == null) return level;
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
count--;
}
level ++;
}
return level;
}
}