0. 总结
- 层序遍历,Queue,addLast、PollFirst
- 前序遍历:Stack,先进后出,先右后左,push,pop
- 中序遍历:Stack,先存左子树,再存右子树
- 后序遍历:Stack,addFirst将原栈顶往下压
- BST中序为递增,反中序为递减
- BST节点大小:左 < 根 < 右
- 前序和中序重建、中序和后序重建
1. 前序遍历:Stack。先进后出,push,pop
- 二叉树的前序遍历
class Solution {
public List preorderTraversal(TreeNode root) {
/*
二叉树的前序遍历
8.24
*/
//BFS做法,栈存节点
ArrayList result = new ArrayList<>();
Stack stack = new Stack<>();
if(root == null){
return result;
}else{
stack.push(root);
}
while(!stack.isEmpty()){
//先进后出,但是如果是第一次,则接收根节点,实现根左右
TreeNode node = stack.pop();
result.add(node.val);
//因为是栈,右节点先进,实现左右顺序
if(node.right != null){
stack.push(node.right);
}
if(node.left != null){
stack.push(node.left);
}
}
return result;
}
}
class Solution {
ArrayList result = new ArrayList<>();
public List preorderTraversal(TreeNode root) {
if(root != null){
result.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
}
return result;
}
}
2. 层序遍历:Queue。先进先出。addLast、pollFirst
- 二叉树的序列化和反序列化
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
//8.29
StringBuilder result = new StringBuilder();
result.append("[");
LinkedList queue = new LinkedList<>();
if(root == null){
return "[]";
}else{
queue.addLast(root);
}
while(!queue.isEmpty()){
TreeNode node = queue.pollFirst();
if(node != null){
result.append(node.val+",");
queue.addLast(node.left);
queue.addLast(node.right);
}else{
result.append("null,");
}
}
result.deleteCharAt(result.length()-1);
result.append("]");
return result.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if(data.equals("[]")){
return null;
}
//提取节点值
String[] str = data.substring(1,data.length()-1).split(",");
TreeNode root = new TreeNode(Integer.parseInt(str[0]));
LinkedList queue = new LinkedList<>();
queue.addLast(root);
int index = 1;
while(!queue.isEmpty()){
TreeNode node = queue.pollFirst();
//重建左右子树
if(!str[index].equals("null")){
node.left = new TreeNode(Integer.parseInt(str[index]));
queue.addLast(node.left);
}
index++;
if(!str[index].equals("null")){
node.right = new TreeNode(Integer.parseInt(str[index]));
queue.addLast(node.right);
}
index++;
}
return root;
}
}
- 二叉树的Z形遍历
class Solution {
public List> zigzagLevelOrder(TreeNode root) {
/*
二叉树Z字形打印
8.24
*/
ArrayList> result = new ArrayList<>();
LinkedList queue = new LinkedList<>();
if(root == null){
return result;
}else{
queue.addLast(root);
}
while(!queue.isEmpty()){
//层存储,因为要Z字形打印,因此使用LinkedList
LinkedList list = new LinkedList<>();
//要根据result的奇偶行来控制存储,先提取result.size()
int floor = result.size();
//提取队列长度
int size = queue.size();
for(int i=0;i
- 二叉树从上到下打印
class Solution {
public List> levelOrder(TreeNode root) {
/*
二叉树的层序遍历:从上往下
8.24
*/
ArrayList> result = new ArrayList<>();
LinkedList queue = new LinkedList<>();
if(root == null){
return result;
}else{
queue.addLast(root);
}
while(!queue.isEmpty()){
//层存储
ArrayList list = new ArrayList<>();
//先提取队列长度
int size = queue.size();
for(int i=0;i
- 二叉树从下往上打印
class Solution {
public List> levelOrderBottom(TreeNode root) {
/*
二叉树层序遍历:从下往上
8.24
*/
//BFS队列实现
ArrayList> result = new ArrayList<>();
LinkedList queue = new LinkedList<>();
if(root == null){
return result;
}else{
queue.addLast(root);
}
while(!queue.isEmpty()){
//层存储,使用ArrayList
ArrayList list = new ArrayList<>();
int size = queue.size();
for(int i=0;i
3. 中序遍历:Stack
- 二叉树中序遍历
class Solution {
public List inorderTraversal(TreeNode root) {
/*
二叉树中序遍历
8.24
*/
//BFS栈实现
ArrayList result = new ArrayList<>();
Stack stack = new Stack<>();
if(root == null){
return result;
}
while(root != null || !stack.isEmpty()){
//每次循环都先到达左子树最左
while(root != null){
stack.push(root);
root = root.left;
}
//接收左子树最左节点,存入
root = stack.pop();
result.add(root.val);
//将节点替换为右子树,重复上述操作
root = root.right;
}
return result;
}
}
class Solution {
ArrayList result = new ArrayList<>();
public List inorderTraversal(TreeNode root) {
if(root != null){
inorderTraversal(root.left);
result.add(root.val);
inorderTraversal(root.right);
}
return result;
}
}
4. 后序遍历:Stack。先进后出。push,pop。addFirst
- 二叉树的后序遍历
class Solution {
public List postorderTraversal(TreeNode root) {
/*
二叉树后序遍历:左右根
8.24
*/
//BFS栈实现
LinkedList result = new LinkedList<>();
Stack stack = new Stack<>();
if(root == null){
return result;
}else{
stack.push(root);
}
while(!stack.isEmpty()){
//接收栈顶
TreeNode node = stack.pop();
//添加到头部,
result.addFirst(node.val);
//先进后出。因为是通过将节点值添加到头部实现左右根的顺序,因此,需要右子树先出栈
if(node.left != null){
stack.push(node.left);
}
if(node.right != null){
stack.push(node.right);
}
}
return result;
}
}
class Solution {
ArrayList result = new ArrayList<>();
public List postorderTraversal(TreeNode root) {
if(root != null){
postorderTraversal(root.left);
postorderTraversal(root.right);
result.add(root.val);
}
return result;
}
}
5. BST相关:中序遍历为递增,反中序遍历为递减
- BST中第k小的元素
class Solution {
int result = 0;
int count = 0;
public int kthSmallest(TreeNode root, int k) {
/*
二叉搜索树中第k小的元素
7.26
*/
//BST中序为递增
if(root == null){
return result;
}
find(root,k);
return result;
}
public void find(TreeNode root,int k){
//递归出口
if(root == null){
return;
}
//左
find(root.left,k);
//层数计数+1
count++;
//如果count == k,提取当前节点值,返回
if(count == k){
result = root.val;
return;
}
//右
find(root.right,k);
}
}
- BST转累加树
class Solution {
//保存当前节点值
int temp = 0;
public TreeNode convertBST(TreeNode root) {
/*
二叉搜索树转累加树
7.26
*/
//BST反中序为递减序列,可以实现累加
if(root == null){
return null;
}
//右
convertBST(root.right);
//叠加上一次
root.val += temp;
//提取本次
temp = root.val;
//左
convertBST(root.left);
return root;
}
}
- 有序数组转BST
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
/*
有序数组转换为BST
8.23
*/
//BST中序遍历为有序序列,提取数组的中位数作为root节点,然后中序递归,建立BST
if(nums.length == 0){
return null;
}
//传入nums用于查找中位数,传入start和end用于计算中位数
return recur(nums,0,nums.length-1);
}
public TreeNode recur(int[] nums,int start,int end){
//递归出口
if(start > end){
return null;
}
//中位数
int middle = start + (end - start)/2;
//提取中位数作为root
TreeNode root = new TreeNode(nums[middle]);
//中序递归重建,左子树[start,middle-1],右子树[middle+1,end]
root.left = recur(nums,start,middle-1);
root.right = recur(nums,middle+1,end);
return root;
}
}
- 有序链表转BST
class Solution {
public TreeNode sortedListToBST(ListNode head) {
/*
有序链表转二叉搜索树
7.25
*/
//找中点,中序递归
if(head == null){
return null;
}
//头和尾
return transfer(head,null);
}
public TreeNode transfer(ListNode head,ListNode tail){
//递归出口
if(head == tail){
return null;
}
//快慢指针找中点
ListNode fast = head;
ListNode slow = head;
while(fast != tail && fast.next != tail){
fast = fast.next.next;
slow = slow.next;
}
//提取中点slow作为root节点
TreeNode root = new TreeNode(slow.val);
root.left = transfer(head,slow);
root.right = transfer(slow.next,tail);
return root;
}
}
- BST的最近公共祖先
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
/*
二叉树最近公共祖先
7.27
*/
//递归左右子树
//递归出口
if(root == null || root == p || root == q){
return root;
}
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left == null){
return right;
}
if(right == null){
return left;
}
return root;
}
}
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//8.29
//遍历,BST,左根右,从小到大
//while true循环,直到找到公共交点位置
while(true){
//左子树都比root节点小,右子树都比root节点大
if(root.val > p.val && root.val > q.val){
root = root.left;
}else if(root.val < p.val && root.val < q.val){
root = root.right;
}else{
return root;
}
}
}
}
- BST的后序遍历序列
class Solution {
public boolean verifyPostorder(int[] postorder) {
//8.29
//单调栈,倒序遍历,找到第一个比右子树小的值的,提取作为root节点,然后比较root节点和左子树的节点值,如果左子树存在比root大的值,返回false
Stack stack = new Stack<>();
int root = Integer.MAX_VALUE;
for(int i=postorder.length-1;i>=0;i--){
//判断当前节点值是否比root节点大,左子树判断
if(postorder[i] > root){
return false;
}
//while循环寻找root节点值w
while(!stack.isEmpty() && postorder[i] < stack.peek()){
root = stack.pop();
}
stack.push(postorder[i]);
}
return true;
}
}
6. DFS相关
- 二叉树中最大路径和(随意节点出发)
class Solution {
int result = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
//8.30
//dfs,提取左右子树本次递归的最大深度
if(root == null){
return 0;
}
dfs(root);
return result;
}
public int dfs(TreeNode root){
if(root == null){
return 0;
}
//左子树路径和
int left = Math.max(dfs(root.left),0);
//右子树路径和
int right = Math.max(dfs(root.right),0);
//本次最大路径和
result = Math.max(root.val + left + right,result);
//返回本次最大路径
return root.val + Math.max(left,right);
}
}
- 路径总和——随机节点
class Solution {
/*
路径总和,随机节点出发
7.26
*/
//DFS+回溯
//这一题的难点在于: 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)
//所以要计算
//1. 以root节点dfs递归
//2. 以root.left节点从root节点开始递归
//3. 以root.right节点从root节点开始递归
public int pathSum(TreeNode root, int sum) {
//1. 递归出口
if(root == null){
return 0;
}
//2. 创建root节点递归结果
int root_val = DFS(root,sum);
//3. 创建root.left节点递归结果(要递归pathSum(),要重新从root.left的root节点开始递归)
int left_val = pathSum(root.left,sum);
//4. 创建root.right节点递归结果(要递归pathSum(),要重新从root.right的root节点开始递归)
int right_val = pathSum(root.right,sum);
//5. 返回结果
return root_val + left_val + right_val;
}
public int DFS(TreeNode node,int sum){
//1. 判断越界
if(node == null){
return 0;
}
//2. sum递减node.val
sum -= node.val;
//3. 如果sum为0,result为1,否则为0
int result;
if(sum == 0){
result = 1;
}else{
result = 0;
}
//4. 继续递归左右子树(记得加上result,继续叠加)
return result + DFS(node.left,sum) + DFS(node.right,sum);
}
}
- 路径总和——根节点
class Solution {
ArrayList> result = new ArrayList<>();
ArrayList list = new ArrayList<>();
public List> pathSum(TreeNode root, int sum) {
/*
路经总和,找路径组合
8.23
*/
dfs(root,sum);
return result;
}
public void dfs(TreeNode node,int sum){
//递归出口
if(node == null){
return;
}
//list先添加当前节点值
list.add(node.val);
//sum递减当前节点值
sum -= node.val;
//如果sum递减到0并且左右子树为空,result添加list。否则继续递归左右子树
if(sum == 0 && node.left == null && node.right == null){
result.add(new ArrayList<>(list));
}else{
dfs(node.left,sum);
dfs(node.right,sum);
}
//回溯
list.remove(list.size()-1);
}
}
- 判断是否存在一条路径
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
/*
判断是否存在到某个值的路径总和
8.23
*/
//要求从根节点开始,所以sum先递减root.val
if(root == null){
return false;
}
sum -= root.val;
//如果sum为0且左右子树都为空,说明存在一条路径
if(sum == 0 && root.left == null && root.right == null){
return true;
}
//递归左右子树,存在一条即可
return hasPathSum(root.left,sum) || hasPathSum(root.right,sum);
}
}
7. 递归相关
- 树的子结构
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
//8.30
//B是否在A的左右子树中,或者B的节点值能和A的左右子树匹配
if(A == null || B == null){
return false;
}
return isSubStructure(A.left,B) || isSubStructure(A.right,B) || compare(A,B);
}
public boolean compare(TreeNode A,TreeNode B){
//true出口,B能够匹配A
if(B == null){
return true;
}
//false出口,B不能匹配A
if(A == null || B == null || A.val != B.val){
return false;
}
return compare(A.left,B.left) && compare(A.right,B.right);
}
}
- 打家劫舍树形
class Solution {
public int rob(TreeNode root) {
/*
打家劫舍,树形
7.26
*/
//偷当前节点和不偷当前节点
//判断空
if(root == null){
return 0;
}
//使用数组接收返回结果
int[] result = MyRob(root);
return Math.max(result[0],result[1]);
}
public int[] MyRob(TreeNode root){
int[] result = new int[2];
//递归出口
if(root == null){
return result;
}
//左子树递归结果
int[] left = MyRob(root.left);
//右子树递归结果
int[] right = MyRob(root.right);
//偷当前节点:当前+不能偷左右
result[0] = root.val + left[1] + right[1];
//不偷当前:左右最大值
result[1] = Math.max(left[0],left[1]) + Math.max(right[0],right[1]);
return result;
}
}
- 二叉树的右视图
class Solution {
ArrayList result = new ArrayList<>();
int depth = 0;
public List rightSideView(TreeNode root) {
/*
二叉树的右视图,先递归右子树,搜完左子树就return。需要一个深度depth变量控制添加每一层的值
8.23
*/
if(root == null){
return result;
}
//当前深度为0
dfs(root,0);
return result;
}
public void dfs(TreeNode root,int curDepth){
//递归出口
if(root == null){
return;
}
//如果当前深度一致
if(curDepth == depth){
result.add(root.val);
depth++;
}
//右视图,搜索右子树
dfs(root.right,curDepth+1);
dfs(root.left,curDepth+1);
}
}
- 二叉树的最近公共祖先
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
/*
二叉树的公共祖先
7.26
*/
//递归左右子树,如果左子树找不到,返回右子树递归结果,反之亦然
//1. 判断越界
if(root == null || p == root || q == root){
return root;
}
//2. 递归左子树
TreeNode left = lowestCommonAncestor(root.left,p,q);
//3. 递归右子树
TreeNode right = lowestCommonAncestor(root.right,p,q);
//4. 如果左子树为null,返回右子树结果
if(left == null){
return right;
}
//5. 如果右子树为null,返回左子树结果
if(right == null){
return left;
}
//6. 否则返回root
return root;
}
}
- 二叉树的最小深度
class Solution {
public int minDepth(TreeNode root) {
/*
二叉树最小深度
8.23
*/
//要考虑左空右不空和右空左不空的情况
if(root == null){
return 0;
}
//如果左子树已经为空,返回右子树递归结果
if(root.left == null && root.right != null){
return minDepth(root.right) + 1;
}
//如果右子树为空,返回左子树递归结果
if(root.right == null && root.left != null){
return minDepth(root.left) + 1;
}
//提取最小值
return Math.min(minDepth(root.left),minDepth(root.right)) + 1;
}
}
- 二叉树的直径
class Solution {
int max = 0;
public int diameterOfBinaryTree(TreeNode root) {
/*
二叉树直径
7.26
*/
//直径等于左子树深度+右子树深度
if(root == null){
return 0;
}
helper(root);
return max;
}
public int helper(TreeNode root){
if(root == null){
return 0;
}
int left = helper(root.left);
int right = helper(root.right);
if(left + right > max){
max = left+ right;
}
return Math.max(left,right)+1;
}
}
- 对称二叉树
class Solution {
public boolean isSymmetric(TreeNode root) {
/*
二叉树镜像,左右子树能否同时到达底部并且节点值一致
8.23
*/
if(root == null){
return true;
}
return Mirror(root.left,root.right);
}
public boolean Mirror(TreeNode left,TreeNode right){
//true出口
if(left == null && right == null){
return true;
}
//false出口
if(left == null || right == null || left.val != right.val){
return false;
}
return Mirror(left.left,right.right) && Mirror(left.right,right.left);
}
}
- 平衡二叉树
class Solution {
public boolean isBalanced(TreeNode root) {
/*
平衡二叉树:左右子树深度不超过1,且左右子树是平衡树
8.23
*/
//递归到树的底部,返回true
if(root == null){
return true;
}
return isBalanced(root.left) && isBalanced(root.right) && Math.abs(Depth(root.left) - Depth(root.right)) <= 1;
}
public int Depth(TreeNode root){
if(root == null){
return 0;
}
return Math.max(Depth(root.left),Depth(root.right)) + 1;
}
}
- 翻转二叉树
class Solution {
public TreeNode invertTree(TreeNode root) {
/*
翻转二叉树
7.26
*/
//递归左右子树
//判断空
if(root == null){
return null;
}
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
}
}
- 合并二叉树
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
/*
合并二叉树
7.26
*/
//递归,选取其中一棵树作为合并后的树
if(t1 == null){
return t2;
}
if(t2 == null){
return t1;
}
t1.val += t2.val;
t1.left = mergeTrees(t1.left,t2.left);
t1.right = mergeTrees(t1.right,t2.right);
return t1;
}
}
8. 重建二叉树
- 前序和中序重建
class Solution {
Map map = new HashMap<>();
int[] pre;
public TreeNode buildTree(int[] preorder, int[] inorder) {
/*
前序和中序构建二叉树
7.25
*/
//递归重建,map存中序,数组存前序
pre = preorder;
for(int i=0;i in_right){
return null;
}
//提取前序的root节点
TreeNode root = new TreeNode( pre[pre_root]);
//提取中序的root节点值
int in_root = map.get(root.val);
//根据前序的root节点重建左右子树
root.left = recur(pre_root+1,in_left,in_root-1);
root.right = recur(pre_root+in_root-in_left+1,in_root+1,in_right);
return root;
}
}
- 中序和后序重建
class Solution {
Map map = new HashMap<>();
int postindex;
public TreeNode buildTree(int[] inorder, int[] postorder) {
/*
中序和后序重建二叉树
7.25
*/
//递归重建,map存中序,index提取后序
postindex = postorder.length-1;
for(int i=0;i in_right){
return null;
}
//提取后序的root接待你
TreeNode root = new TreeNode(postorder[postindex--]);
//提取中序的root节点值
int in_root = map.get(root.val);
//根据后序的root节点重建,先右后左
root.right = recur(postorder,in_root+1,in_right);
root.left = recur(postorder,in_left,in_root-1);
return root;
}
}
- 二叉树展开为链表
class Solution {
public void flatten(TreeNode root) {
/*
二叉树展开为链表
7.25
*/
//递归左子树形成左链表,保存右子树,将右子树变成左子树,将左子树置空,while到右子树的最右端,拼接保存的右子树
if(root == null){
return;
}
//递归左右子树到底部
flatten(root.left);
flatten(root.right);
//保存右子树
TreeNode temp = root.right;
//将右子树替换为左子树
root.right = root.left;
//将左子树置空
root.left = null;
//while到右子树的最右端
while(root.right != null){
root = root.right;
}
//将右子树拼接到底部
root.right = temp;
}
}