二叉树
镜像二叉树
1.把左右根交换即可
class Solution { public TreeNode mirrorTree(TreeNode root) { if (root == null) return null; TreeNode temp = root.left; root.left = root.right; root.right = temp; mirrorTree(root.left); mirrorTree(root.right); return root; } }
|
找出克隆二叉树中的相同节点
public final TreeNode getTargetCopy(final TreeNode original, final TreeNode cloned, final TreeNode target) { if (original == null) return null; if (original == target) return cloned; TreeNode left = getTargetCopy(original.left, cloned.left, target); if (left!=null) return left; return getTargetCopy(original.right, cloned.right, target); }
|
HomeWork
自定义树结点
public class TreeNode { char val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(char val) { this.val = val; } TreeNode(char val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; }
|
1. 先根序列构造二叉树:A B null D null null C null null
static int count = 0;
public TreeNode CteateTree(char[] arr) { TreeNode node = null; if (count < arr.length) { char val = arr[count++]; if (val != '^') { node = new TreeNode(val); node.left = CteateTree(arr); node.right = CteateTree(arr); } } return node; }
|
2.对于1中生成的二叉树进行前序、中序、后序遍历。
public static void preOrderTravera(TreeNode node){ if(node!=null) { System.out.print(node.val + " "); preOrderTravera(node.left); preOrderTravera(node.right); } else { System.out.print('^'); System.out.print(' '); } }
public static void inOrderTravera(TreeNode node){ if(node != null) {
inOrderTravera(node.left); System.out.print(node.val + " "); inOrderTravera(node.right); } else { System.out.print('^'); System.out.print(' '); } }
public static void postOrderTravera(TreeNode node){ if(node != null) { postOrderTravera(node.left); postOrderTravera(node.right); System.out.print(node.val + " "); } else { System.out.print('^'); System.out.print(' '); } }
|
3. 计算1中生成的二叉树结点总数。
static int num=0;
public int TreeNodeNum(TreeNode node,) { if (node != null) { num += 1; TreeNodeNum(node.left); TreeNodeNum(node.right); } return num; }
|
4. 计算1中生成二叉树的高度
public int maxDepth(TreeNode root) { if(root==null){ return 0; } else{ int leftNode =maxDepth(root.left); int rightNode=maxDepth(root.right); return Math.max(leftNode,rightNode)+1; } }
|
5.计算1中生成二叉树中度为1的节点数、度为2的结点数和叶子数。
public int LeafNodeCount(TreeNode root) { if (root == null) { return 0; } if (root.left == null && root.right == null) { return 1+LeafNodeCount(root.left)+LeafNodeCount(root.right); } return LeafNodeCount(root.left) + LeafNodeCount(root.right); }
public int OneNodeCount(TreeNode root) { if (root == null) { return 0; } if (root.left == null && root.right != null || root.left != null && root.right == null) { return 1+OneNodeCount(root.left)+OneNodeCount(root.right); } return OneNodeCount(root.left) + OneNodeCount(root.right); }
public int DoubleNodeCount(TreeNode root) { if (root == null) { return 0; } if (root.right != null && root.left != null) { return 1+DoubleNodeCount(root.left) + DoubleNodeCount(root.right); } return DoubleNodeCount(root.left) + DoubleNodeCount(root.right); }
|
6.按照下面两个序列生成二叉树:先序:ABHFDECKG ;中序:HBDFAEKCG
前序+中序构造二叉树
先序:根 [左子树] [右子树]
中序:[左子树] 根 [右子树]
思路:只要遍历中序找到根节点,利用双指针确认左右子树遍历结果的长度,再利用先序方式构造即可
循环寻界+递归构造树
public TreeNode buildTrees(char [] pre,char [] in) {
TreeNode root=buildTree(pre,0,pre.length-1,in,0,in.length-1); return root; }
private TreeNode buildTree(char [] pre,int PreLeft,int PreRight,char [] in,int inLeft,int inRight) {
if(PreLeft>PreRight||inLeft>inRight) return null;
TreeNode root=new TreeNode(pre[PreLeft]);
for(int i=inLeft;i<=inRight;i++){ if(in[i]==pre[PreLeft]){
root.left=buildTree(pre,PreLeft+1,PreLeft+i-inLeft,in,inLeft,i-1);
root.right=buildTree(pre,i-inLeft+PreLeft+1,PreRight,in,i+1,inRight); break; } } return root; }
|
哈希表优化循环子过程
public TreeNode buildTreeTwo(char [] pre,char [] in){ int PreLen = pre.length; int InLen = pre.length; Map<Character,Integer> map = new HashMap<>(PreLen); for (int i =0;i<InLen;i++){ map.put(in[i],i); } return buildTreeTwo(pre,0,PreLen-1,map,0,InLen-1); }
private TreeNode buildTreeTwo(char[]pre,int PreLeft,int PreRight,Map<Character,Integer> map,int InLeft,int InRight){ if(PreLeft>PreRight||InLeft>InRight){ return null; } char val = pre[PreLeft]; TreeNode root = new TreeNode(val); int index = map.get(val); root.left=buildTreeTwo(pre,PreLeft+1,index-InLeft+PreLeft,map,InLeft,index-1); root.right=buildTreeTwo(pre,index-InLeft+PreLeft+1,PreRight,map,index+1,InRight); return root; }
|
栈方法迭代
public TreeNode buildTree(char[] preorder, char[] inorder) { if (preorder == null || preorder.length == 0) { return null; } TreeNode root = new TreeNode(preorder[0]); Deque<TreeNode> stack = new LinkedList<TreeNode>(); stack.push(root); int inorderIndex = 0; for (int i = 1; i < preorder.length; i++) { int preorderVal = preorder[i]; TreeNode node = stack.peek(); if (node.val != inorder[inorderIndex]) { node.left = new TreeNode(preorderVal); stack.push(node.left); } else { while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) { node = stack.pop(); inorderIndex++; } node.right = new TreeNode(preorderVal); stack.push(node.right); } } return root; }
|
二叉树遍历
建立树节点
public class TreeNode{ int val; TreeNode left; TreeNode right; TreeNode(){} TreeNOde(int val){ this val = val; } TreeNode(int val,TreeNode left,TreeNode right){ this.val = val; this.left=left; this.right=right; } }
|
前序遍历
public static void preOrderTraveral(TreeNode node){ if(node==null){ return; } System.out.print(node.data+""); preOrderTraveral(node.left); preOrderTraveral(node.right); }
|
中序遍历
public static void inOrderTraveral(TreeNode node){ if(node == null){ return; } inOrderTraveral(node.left); System.out.print(node.data+""); inOrderTraveral(node.right); }
|
后序遍历
public static void postOrderTraveral(TreeNode node){ if(node == null){ return; } postTraveral(node.left); postTraveral(node.right); System.out.print(node.data+""); }
|
层次遍历
public void leverOrder(TreeNode root) { Queue<TreeNode> storage = new LinkedList<TreeNode>(); if (root == null) { return; } storage.offer(root); while(!storage.isEmpty()){ TreeNode cur = storage.poll(); System.out.print(cur.val+" "); if (cur.left!=null){ storage.offer(cur.left); } if (cur.right!=null) { storage.offer(cur.right); } } }
|
Morris遍历
https://zitiu.top/2022/10/24/Morris%20%E9%81%8D%E5%8E%86/
leetcode
总思路
只要提到树的话就几乎都会涉及到递归和回溯.
比较常用的算法思想就是深度和广度优先搜索
617.合并二叉树
这道题我的思路很简单,就是递归遍历,进行创新节点的操作
可以分三种情况
- 两个节点均为null值
- 一个节点为null,一个不为null值
- 两个节点都不是null值
实现1:深度优先搜索
public TreeNode merageTrees(TreeNode r1,TreeNode r2){ if(r1==null) return r2; if(r2==null) return r1; TreeNode metaTree = new TreeNode(r1.val+r2.val); metaTree.left = merageTrees(r1.left,r2.left); metaTree.right= merageTrees(r1.right,r2.right); return metaTree; }
|
实现2:广度优先搜索
- 主要实现:构建三个队列分别储存3颗树的每个节点
- 每次从队列种取出一个节点,判断两个原始树的结点是否为空
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { if (t1 == null) { return t2; } if (t2 == null) { return t1; } TreeNode merged = new TreeNode(t1.val + t2.val); Queue<TreeNode> queue = new LinkedList<TreeNode>(); Queue<TreeNode> queue1 = new LinkedList<TreeNode>(); Queue<TreeNode> queue2 = new LinkedList<TreeNode>(); queue.offer(merged); queue1.offer(t1); queue2.offer(t2); while (!queue1.isEmpty() && !queue2.isEmpty()) { TreeNode node = queue.poll(), node1 = queue1.poll(), node2 = queue2.poll(); TreeNode left1 = node1.left, left2 = node2.left, right1 = node1.right, right2 = node2.right; if (left1 != null || left2 != null) { if (left1 != null && left2 != null) { TreeNode left = new TreeNode(left1.val + left2.val); node.left = left; queue.offer(left); queue1.offer(left1); queue2.offer(left2); } else if (left1 != null) { node.left = left1; } else if (left2 != null) { node.left = left2; } } if (right1 != null || right2 != null) { if (right1 != null && right2 != null) { TreeNode right = new TreeNode(right1.val + right2.val); node.right = right; queue.offer(right); queue1.offer(right1); queue2.offer(right2); } else if (right1 != null) { node.right = right1; } else { node.right = right2; } } } return merged; }
|
100.相同的树
- 树的递归判断
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 false; return isSameTree(p,left,q.left)&&isSameTree(p.right,q.right); }
|
对称二叉树
- 基本和相同树的判断思想是一样的,只要把左右两个孩子分别当作新的结点进行比较
public boolean isSymmetric(TreeNode root) { return isSameTree(root,root); } public boolean isSameTree(TreeNode leftnode,TreeNode rightnode){ if(leftnode==null&&rightnode==null){ return true; } if(leftnode==null||rightnode==null){ return false; } return leftnode.val==rightnode.val&&isSameTree(leftnode.left,rightnode.right)&&isSameTree(leftnode.right,rightnode.left); }
|
226.翻转二叉树
- 思路也是十分的简单,像数组的位置变换一样,定义一个辅助变量,而这边定义一个新的树对象来储存。
public TreeNode invertTree(TreeNode root) { if (root == null) return null; TreeNode rightTree = root.right; root.right = invertTree(root.left); root.left = invertTree(rightTree); return root; }
|
111.二叉树的最小深度
- 做法几乎于最大深度差不多,只是把max改成min罢了
- 但是要注意的是空节点是不需要比较的。
pubilc int minDepth(TreeNode root){ if(root==null){ return 0; } if(root.right==null&&root.left!=null){ return 1+minDepth(root.left); } if(root.left==null&&root.right!=null){ return 1+minDepth(root.right); } return Math.min(minDepth(root.left),minDepth(root.right))+1; }
|
637.二叉树的层平均值
- 我第一反应是一定要用到层次遍历,那么每层的结点个数我是应该怎么确定呢?
- 然而实际上确实需要用到层次遍历的思想,而且还需要一个计数器
public List<Double> averageOfLevels(TreeNode root) { List<Double> storage = new ArrayList<Double>(); Queue<TreeNode> stoge = new LinkedList<TreeNode>(); stoge.offer(root); while(!stoge.isEmpty()){ double sum = 0.0; int size = stoge.size(); for(int i = 0;i<size;i++){ root = stoge.poll(); sum += root.val; if(root.left!=null){ stoge.offer(root.left); } if(root.right!=null){ stoge.offer(root.right); } } storage.add(sum/size); } return storage; }
|
- 步骤解析
- 在while之前把根结点代入队列。
- 开始while循环,重置sum值,目的是为了把每层的的结点总值区分开添入List中
- 获取队列的长度,队列的长度在这里其实就是这层结点的总数
- 比如代入root后,然后元素出队,因为此时的队列中只有root一个元素,所以出队root后,队列为空,停止循环,然后计算sum值,sum值得计算是用for循环本层得结点数得次数后得到得,然后把sum/size添加入List中
- 判断,那么两个if语句为了让下一个左右结点得入队,空则不入,不空则入。
404.左子叶之和
- 首先需要的是找到叶子节点,如果是就回溯到上一个结点输出左子叶,如果不是的话就往下递归。
- 递归
public int sumOfLeftLeaves(TreeNode root) { int sum = 0; if(root==null){ return 0; } if(root.left!=null&&root.left.right==null&&root.left.left==null){ sum += root.left.val; } return sumOfLeftLeaves(root.left)+sumOfLeftLeaves(root.right)+sum; }
|
- 队列(广度优先搜索)
public int sumOfLeftLeaves(TreeNode root) { Queue<TreeNode> storage = new LinkedList<TreeNode>(); int sum = 0; storage.offer(root); if (root == null) { return 0; } while(!storage.isEmpty()){ TreeNode node = storage.poll(); if(node.left!=null){ if(node.left.right==null&&node.left.left==null){ sum+=node.left.val; } else{ storage.offer(node.left); } } if(node.right!=null){ if(!(node.right.left==null&&node.right.right==null)){ storage.offer(node.right); } } } return sum; }
|