面试算法题——二叉树整理

---
二叉树的精髓在于
递归的调用思想(自顶向下、自底向上)
层序遍历的两种思想(递归、栈)
相应的又有很多其他的应用
---

1.二叉树的前、中、后序遍历方法(递归、非递归)


2.二叉树的层序遍历


3.二叉树的递归解决问题


|-- 最大深度、最小深度、最大宽度、节点个数、二叉树的直径

|-- 判断对称二叉树、相同二叉树、翻转二叉树、二叉树子树、合并二叉树、平衡二叉树

|-- 二叉树路径和、最大路径和、第k大的节点、两节点的最大距离

|-- 公共祖先

|-- 序列化和反序列化、重构二叉树(前+中、中+后)

|-- N叉树的前、中、后序遍历

<!--二叉树1.二叉树的前、中、后序遍历方法(递归、非递归)|-- 前序遍历:ArrayList<Integer> list = new ArrayList<>();public List<Integer> preorderTraversal(TreeNode root) {if(root==null){return list;}else{list.add(root.val);if(root.left!=null){preorderTraversal(root.left);}if(root.right!=null){preorderTraversal(root.right);}}return list; }|-- 中序遍历:ArrayList<Integer> list  =  new ArrayList<>();public List<Integer> inorderTraversal(TreeNode root) {if(root==null){return list;}else{if(root.left!=null){inorderTraversal(root.left);}list.add(root.val);if(root!=null){inorderTraversal(root.right);}return list;}}|-- 后序遍历:ArrayList<Integer> list = new ArrayList<>();public List<Integer> postorderTraversal(TreeNode root) {if(root==null){return list;}else{if(root.left!=null){postorderTraversal(root.left);}if(root.right!=null){postorderTraversal(root.right);}list.add(root.val);return list;}}2.二叉树的层序遍历|-- 用深度遍历法dfsArrayList<List<Integer>> list = new ArrayList<>();public List<List<Integer>> levelOrder(TreeNode root) {if(root==null){return list;}else{int index = 1;dfs(root,index,list.size());return list;}}public void dfs(TreeNode node,int index,int size){if(index>size){list.add(new ArrayList<Integer>());}//层数是从1开始,而list的索引是从0开始。所以index-1list.get(index-1).add(node.val);if(node.left!=null){dfs(node.left,index+1,list.size());}if(node.right!=null){dfs(node.right,index+1,list.size());}}|-- 广度遍历法public List<Integer> levelOrder(TreeNode root){LinkedList<TreeNode> queue = new LinkedList<>();ArrayList<Integer> list = new ArrayList<>();if(root==null){return list;}else{queue.offer(root);while(!queue.isEmpty()){TreeNode node = queue.poll();list.add(node.val);if(node.left!=null){queue.offer(node.left);}if(node.right!=null){queue.offer(node.right);}}}return list;}3.二叉树的递归解决问题
|-- 最大深度、最小深度、最大宽度、节点个数、二叉树的直径二叉树的最大深度(层数):public int TreeDepth(TreeNode root) {if(root==null){return 0;}int left=TreeDepth(root.left)+1;int right=TreeDepth(root.right)+1;return Math.max(left,right);}附录:完全二叉树的深度public int nodeCount(TreeNode node){int depth=0;while(node!=null){depth++;node = node.left;}return depth;}二叉树的最小深度public int minDepth(TreeNode root) {if(root == null)return 0;int left = minDepth(root.left);int right = minDepth(root.right);//因为我们不知道left还是right的长度是0,所以此时用左加右加1!return (left == 0 || right == 0) ? left + right + 1 : Math.min(left, right) + 1;}二叉树的最大宽度:每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。public int widthOfBinaryTree(TreeNode root) {Queue< PositionTreeNode> queue = new LinkedList();int dep = 0, left = 0, ans = 0;queue.offer(new PositionTreeNode(root,0,0));while(!queue.isEmpty()){PositionTreeNode treeNode = queue.poll();//根据满二叉树的特点来标记位置if(treeNode.node!=null){queue.offer(new PositionTreeNode(treeNode.node.left,treeNode.depth+1,treeNode.pos*2));queue.offer(new PositionTreeNode(treeNode.node.right,treeNode.depth+1,treeNode.pos*2+1));//刚进入下一层时,需要重置最左端节点的位置。//第一个dep不等于node.dep就说明是第一个进入下一层的节点//也就是此节点的pos位置就是最左端的节点位置if(dep!=treeNode.depth){dep = treeNode.depth;left = treeNode.pos;}ans = Math.max(ans,treeNode.pos-left+1);}}return ans;}class  PositionTreeNode {TreeNode node;int depth, pos;PositionTreeNode(TreeNode n, int d, int p) {node = n;depth = d;pos = p;}}二叉树的节点个数:public int getNodeNumRec(TreeNode root) {if (root == null) {return 0;}             return getNodeNumRec(root.left) + getNodeNumRec(root.right) + 1;}4.完全二叉树(叶子节点都在左边)的节点个数
二叉树的基本概念和类型:https://www.cnblogs.com/sunshineliulu/p/7775063.htmlpublic int countNodes(TreeNode root) {if(root==null){return 0;}int leftDepth = nodeCount(root.left);int rightDepth = nodeCount(root.right);if(leftDepth ==rightDepth){return (1<<leftDepth) + countNodes(root.right);}else{return (1<<rightDepth) + countNodes(root.left);}}public int nodeCount(TreeNode node){int depth=0;while(node!=null){depth++;node = node.left;}return depth;}二叉树的直径:任意两个结点路径长度中的最大值int num = 0;public int diameterOfBinaryTree(TreeNode root){depth(root);return num;}public int depth(TreeNode node){if(node==null){return 0;}else{int leftdepth = depth(node.left);int rightdepth = depth(node.right);num = Math.max(num,leftdepth+rightdepth);//保存的最大的左子树与右子树深度之和就是最大的直径return Math.max(leftdepth,rightdepth)+1;//子树的深度就是左子树、右子树中最大值+1}}|-- 判断对称二叉树、相同二叉树、翻转二叉树、二叉树子树、合并二叉树、平衡二叉树1.对称二叉树:递归法:public  boolean isSymmetric(TreeNode root){return root == null || symmetric(root.left, root.right);}public  boolean symmetric(TreeNode p, TreeNode q){if(p==null && q==null){return true;}if(p==null || q==null || p.val!=q.val){return false;}return symmetric(p.left,q.right)&&symmetric(p.right,q.left);}入栈抵消法:public boolean isSymmetric2(TreeNode root){return root == null || symmetric2(root.left, root.right);}public boolean symmetric2(TreeNode node1,TreeNode node2){LinkedList<TreeNode> queue = new LinkedList<>();queue.offer(node1);queue.offer(node2);while(!queue.isEmpty()){TreeNode left = queue.poll();TreeNode right = queue.poll();//1.只需要判断当前节点//2.加上空值判断就不需要判断左右子节点是否为空了if(left==null && right==null){continue;}//1.如果值不相等,则直接返回false//2.如果当前节点有一个为空则返回falseif((left==null || right==null) ||(left.val != right.val)){return false;}queue.offer(left.left);queue.offer(right.right);queue.offer(left.right);queue.offer(right.left);}return true;}2.相同二叉树(同理)public boolean isSameTree(TreeNode p, TreeNode q) {//双指针,判断if(p==null && q==null){return true;}if(p == null || q == null){return false;}return (p.val == q.val) && isSameTree(p.left,q.left) && isSameTree(p.right,q.right);}3.翻转二叉树简洁递归版public TreeNode invertTree3(TreeNode root) {if (root == null) {return null;}root.left = invertTree3(root.right);root.right = invertTree3(root.left);return root;}详细递归版public TreeNode invertTree(TreeNode root) {//递归函数的终止条件,节点为空时返回if(root==null) {return null;}//下面三句是将当前节点的左右子树交换TreeNode tmp = root.right;root.right = root.left;root.left = tmp;//递归交换当前节点的 左子树invertTree(root.left);//递归交换当前节点的 右子树invertTree(root.right);return root;}逐层入栈法public TreeNode invertTree2(TreeNode root) {if(root==null) {return null;}//将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素LinkedList<TreeNode> queue = new LinkedList<>();queue.add(root);while(!queue.isEmpty()) {//每次都从队列中拿一个节点,并交换这个节点的左右子树TreeNode tmp = queue.poll();TreeNode left = tmp.left;tmp.left = tmp.right;tmp.right = left;//如果当前节点的左子树不为空,则放入队列等待后续处理if(tmp.left!=null) {queue.add(tmp.left);}//如果当前节点的右子树不为空,则放入队列等待后续处理if(tmp.right!=null) {queue.add(tmp.right);}}//返回处理完的根节点return root;}3.二叉树子树,判断一棵树t是否是另一棵树s的子树public boolean isSubtree(TreeNode s, TreeNode t) {if(s==null){return false;}else{return isSame(s,t) || isSubtree(s.left,t) || isSubtree(s.right,t);}}public boolean isSame(TreeNode p, TreeNode q){if(p ==null && q == null){return true;}if(p ==null || q ==null || p.val != q.val){return false;}return isSame(p.left, q.left) && isSame(p.right, q.right);}4.合并二叉树public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {if(t1==null || t2 ==null){return t1==null?t2:t1;}else{t1.val = t1.val+t2.val;t1.left = mergeTrees(t1.left,t2.left);t1.right = mergeTrees(t1.right,t2.right);return t1;}}5.平衡二叉树理解:左旋:右子树太长了,把它匀到左边。右旋同理。1.先将根节点设置为新节点,将原左子树还是设为新的左子树2.再把右子树的左子树设为新的右子树3.把新节点作为右子树的 left,右子节点作为新的根节点双旋转:并不是子树直接左旋右旋就能实现平衡左旋时,右子节点的左子树高度 > 右子节点的右子树高度,要先对子树进行右旋判断是否为平衡二叉树public boolean isBalanced2(TreeNode root) {if(root==null){return true;}else{int leftHeight = depth(root.left);int rightHeight = depth(root.right);if(leftHeight-rightHeight>1 || rightHeight-leftHeight>1){return false;}else{return isBalanced(root.left)&&isBalanced(root.right);}}}BST——> AVL|-- 二叉树路径和、最大路径和、第k大的节点、两节点的最大距离1.某路径和:public boolean hasPathSum2(TreeNode root, int sum) {if (root == null) {return false;} else {//广度遍历,保存每一层的和//问题在于原地更新新的和值,所以此时不用ArrayList反而用LInkedListLinkedList<TreeNode> queue = new LinkedList<>();LinkedList<Integer> list = new LinkedList<>();queue.offer(root);list.offer(root.val);while (!queue.isEmpty()) {TreeNode node = queue.poll();int num = list.poll();//如果此处一直poll下面不判断返回,最后所有都会被poll出去没有元素if (node.left == null && node.right == null) {if (num == sum) {return true;}continue;}if (node.left != null) {queue.offer(node.left);list.offer(node.left.val + num);}if (node.right != null) {queue.offer(node.right);list.offer(node.right.val + num);}}return false;}}2.第k大节点:二叉搜索树中序遍历出来是有序数组public int kthLargest2(TreeNode root, int k) {ArrayList<Integer> list = new ArrayList<>();inOrder2(root,list);return list.get(k-1);}public void inOrder2(TreeNode node,ArrayList<Integer> list){if(node==null){return;}else{inOrder2(node.right,list);list.add(node.val);inOrder2(node.left,list);}}|-- 公共祖先1.二叉树的公共祖先:思想在判断两个节点是否在同一棵子树public TreeNode lowestCommonAncestor236(TreeNode root, TreeNode p, TreeNode q) {if(root==null || root==p |root==q){return root;}TreeNode left = lowestCommonAncestor236(root.left,p,q);TreeNode right = lowestCommonAncestor236(root.right,p,q);if(left == null && right == null) return null;if(left==null){return right;}if(right==null){return left;}return root;}2.二叉树的公共祖先public TreeNode lowestCommonAncestor235(TreeNode root, TreeNode p, TreeNode q) {if(p.val<root.val && q.val<root.val){return lowestCommonAncestor235(root.left,p,q);}if(p.val>root.val && q.val>root.val){return lowestCommonAncestor235(root.right,p,q);}return root;}|-- 序列化和反序列化、重构二叉树(前+中、中+后)1.序列化二叉树public String serialize(TreeNode root) {StringBuilder str = new StringBuilder();serializeTreeNode(root,str);return str.toString();}public void  serializeTreeNode(TreeNode node,StringBuilder str){if(node==null){str.append("None,");}else{str.append(Integer.toString(node.val)).append(",");serializeTreeNode(node.left,str);serializeTreeNode(node.right,str);}}2.反序列化二叉树public TreeNode deserialize(String data) {String[] list = data.split(",");ArrayDeque<String> arr = new ArrayDeque<>(Arrays.asList(list));return deserializeArr(arr);}public TreeNode deserializeArr(ArrayDeque<String> arr){if(arr.getFirst().equals("None")){arr.removeFirst();return null;}else{TreeNode root = new TreeNode(Integer.valueOf(arr.getFirst()));arr.removeFirst();root.left = deserializeArr(arr);root.right = deserializeArr(arr);return root;}}3.重构二叉树:前序+中序int[] preOrder;HashMap<Integer,Integer> map = new HashMap<>();public TreeNode buildTree(int[] preOrder,int[] inOrder){this.preOrder = preOrder;for(int i=0;i<inOrder.length;i++){map.put(inOrder[i],i);}return recur(0,0,inOrder.length-1);}public TreeNode recur(int rootIndex,int left,int right){if(left>right){return null;}int index = map.get(preOrder[rootIndex]);TreeNode node = new TreeNode(preOrder[rootIndex]);node.left = recur(rootIndex+1,left,index-1);node.right = recur(rootIndex+index-left+1,index+1,right);return node;}4.重构二叉树:中序+后序|-- N叉树的前、中、后序遍历
N叉树的定义:
class NTreeNode{int val;List<NTreeNode> children;public NTreeNode(int _val, List<NTreeNode> _children) {val = _val;children = _children;}
}1.前序遍历//1.递归法public List<Integer> postorder(NTreeNode root) {List<Integer> res = new ArrayList<>();if(root == null){return res;}else{myposorder(root,res);return res;}}private void myposorder(NTreeNode node,List<Integer> res){if(node==null){return;}else{for(NTreeNode nodes:node.children){myposorder(nodes,res);}res.add(node.val);}}//2.迭代法public List<Integer> postorder2(NTreeNode root) {List<Integer> list  = new ArrayList<>();if(root==null){return list;}LinkedList<NTreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {NTreeNode node = queue.poll();list.add(node.val);for (NTreeNode nodes : node.children) {queue.offer(nodes);}}Collections.reverse(list);return list;}
-->

【试算法题梳理】——二叉树相关推荐

  1. 43. 盘点那些必问的数据结构算法题之二叉树基础

    盘点那些必问的数据结构算法题之二叉树基础 0 概述 1 定义 2 基本操作 1) 创建结点 2) BST 插入结点 3) BST 删除结点 4) BST 查找结点 5)BST 最小值结点和最大值结点 ...

  2. 【经典算法题】二叉树的最近公共祖先

    [经典算法题]二叉树的最近公共祖先 Leetcode 0235 二叉搜索树的最近公共祖先 题目描述:Leetcode 0235 二叉搜索树的最近公共祖先 分析 本题的考点:LCA(最近公共祖先). 关 ...

  3. 让HomeBrew作者面试谷歌翻车的经典算法题 反转二叉树 Node.js 版

    var invertTree = function(root) {if(root === null){return root}let tmpLeft = root.left;root.left = r ...

  4. LeetCode 148. Sort List--面试算法题--C++,Python解法

    LeetCode 148. Sort List–面试算法题–C++,Python解法 LeetCode题解专栏:LeetCode题解 LeetCode 所有题目总结:LeetCode 所有题目总结 大 ...

  5. LeetCode 93. Restore IP Addresses--面试算法题--Python解法

    题目地址:Restore IP Addresses - LeetCode Given a string containing only digits, restore it by returning ...

  6. LeetCode 445. Add Two Numbers II--面试算法题--C++,Python解法

    题目地址:Add Two Numbers II - LeetCode You are given two non-empty linked lists representing two non-neg ...

  7. java 所有路径算法_经典算法题:二叉树的所有路径

    一.题目 给定一个二叉树,返回所有从根节点到叶子节点的路径. 二.思路 回溯算法 三.实现 public List binaryTreePaths(TreeNode root) { List res ...

  8. leetcode算法题--重建二叉树

    原题链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/ TreeNode* buildTree(vector<int& ...

  9. leetcode算法题--分裂二叉树的最大乘积

    原题链接:https://leetcode-cn.com/problems/maximum-product-of-splitted-binary-tree/ 后续遍历+记忆化 vector<lo ...

最新文章

  1. NOIP2005普及组第4题 循环
  2. python3线程中的锁机制
  3. Unable to handle kernel paging request at virtual address 问题定位
  4. NoSQL 非关系数据库
  5. mybatis批量插入oracle报表达式,mybatis oracle两种方式批量插入数据
  6. Python基础---容器集合Set
  7. 调用exe文件(一般处理登陆安全窗口)+睡眠等待(--------------------)
  8. Windows 10正式版21H2更新:之后功能性更新将减为年更
  9. scala学习-scala中的特殊符号使用
  10. 初学者python笔记(元组、字典、集合详解)
  11. Javascript - demo 与 捷径
  12. 创建hadoop 归档文件
  13. android APN的打开与关闭
  14. Oracle 创建函数
  15. EPSG:900913 与 EPSG:4326 转换方法
  16. m1发卡器支持java_友我M1卡通用版的发卡充值软件
  17. 17款现代风格的免费英文字体,分享给设计师们
  18. IMX6ULL UART5配置错误imx6ul-pinfunc.h
  19. class com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 recipient is not exist
  20. 在华清远见学习嵌入式开发的总结

热门文章

  1. 微信公众号点击菜单出现白屏问题探究
  2. android+照相软件,韩国很火的照相app
  3. python线性回归分析看相关性_机器学习入门:相关性分析之线性回归
  4. intval()和int()
  5. Autodesk的照片建模云服务—Autodesk ReCap 360 photo
  6. 霹雳吧啦wz学习笔记1_卷积神经网络
  7. 恶意软件的历史和应对措施
  8. MPLS:多协议标签交换
  9. Win11打字不显示选字框怎么办?Win11打字不显示选字框的解决方法
  10. allegro-Could not create new pin inst: PA15/JTDI.