问题1: 对称的二叉树
原题:对称二叉树
描述
给定一棵二叉树,判断其是否是自身的镜像(即:是否对称)
例如: 下面这棵二叉树是对称的:
下面这棵二叉树不对称:
数据范围:节点数满足 0≤n≤1000,节点上的值满足 ∣val∣≤1000
要求:空间复杂度 O(n),时间复杂度 O(n)
备注:你可以用递归和迭代两种方法解决这个问题
示例
示例1
输入:{1,2,2,3,4,4,3}
返回值:true
示例2
输入:{8,6,9,5,7,7,5}
返回值:false
题解
Java代码实现:
public class Solution { boolean recursion(TreeNode root1, TreeNode root2){ //可以两个都为空 if(root1 == null && root2 == null) return true; //只有一个为空或者节点值不同,必定不对称 if(root1 == null || root2 == null || root1.val != root2.val) return false; //每层对应的节点进入递归比较 return recursion(root1.left, root2.right) && recursion(root1.right, root2.left); } boolean isSymmetrical(TreeNode pRoot) { return recursion(pRoot, pRoot); } }
思路:前序遍历的时候我们采用的是“根左右”的遍历次序,如果这棵二叉树是对称的,即相应的左右节点交换位置完全没有问题,那我们是不是可以尝试“根右左”遍历,按照轴对称图像的性质,这两种次序的遍历结果应该是一样的。
不同的方式遍历两次,将结果拿出来比较看起来是一种可行的方法,但也仅仅可行,太过于麻烦。我们不如在遍历的过程就结果比较了。而遍历方式依据前序递归可以使用递归。
问题2:合并二叉树
原题:合并二叉树
描述
已知两颗二叉树,将它们合并成一颗二叉树。合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替。例如,两颗二叉树是:
Tree1:
Tree2:
合并后的树为:
数据范围:树上节点数量满足 0≤n≤500,树上节点的值一定在32位整型范围内。
进阶:空间复杂度 O(1) ,时间复杂度 O(n)
示例
示例1
输入:{1,3,2,5},{2,1,3,#,4,#,7}
返回值:{3,4,5,5,4,#,7}
说明:如题面图
示例2
输入:{1},{}
返回值:{1}
题解
Java代码实现: import java.util.*; public class Solution { public TreeNode mergeTrees (TreeNode t1, TreeNode t2) { //若只有一个节点返回另一个,两个都为null自然返回null if (t1 == null) return t2; if (t2 == null) return t1; //根左右的方式递归 TreeNode head = new TreeNode(t1.val + t2.val); head.left = mergeTrees(t1.left, t2.left); head.right = mergeTrees(t1.right, t2.right); return head; } }
思路: 要将一棵二叉树的节点与另一棵二叉树相加合并,肯定需要遍历两棵二叉树,那我们可以考虑同步遍历两棵二叉树,这样就可以将每次遍历到的值相加在一起。遍历的方式有多种,这里推荐前序递归遍历。
问题3:二叉树的镜像
原题:二叉树的镜像
描述
操作给定的二叉树,将其变换为源二叉树的镜像。
数据范围:二叉树的节点数 0≤n≤1000 , 二叉树每个节点的值 0≤val≤1000
要求: 空间复杂度 O(n) 。本题也有原地操作,即空间复杂度 O(1) 的解法,时间复杂度 O(n)
比如:源二叉树
镜像二叉树
示例
示例1
输入:{8,6,10,5,7,9,11}
返回值:{8,10,6,11,9,7,5}
说明:如题面所示
示例2
输入:{}
返回值:{}
题解
Java代码实现:
public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param pRoot TreeNode类 * @return TreeNode类 */ public TreeNode Mirror (TreeNode pRoot) { // write code here if(pRoot == null) return null; // 构建辅助栈 Stack<TreeNode> stack = new Stack<>(); // 根节点入栈 stack.add(pRoot); while(!stack.isEmpty()) { // 节点出栈 TreeNode node = stack.pop(); // 根节点的左右子树入栈 if(node.left != null) stack.add(node.left); if(node.right != null) stack.add(node.right); // 左右子树交换 TreeNode tmp = node.left; node.left = node.right; node.right = tmp; } return pRoot; } }
思路:主要是利用栈(或队列)遍历树的所有节点 node ,并交换每个 node 的左 / 右子节点。
问题4:重建二叉树
原题:重建二叉树
描述
给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param pRoot TreeNode类 * @return TreeNode类 */ public TreeNode Mirror (TreeNode pRoot) { // write code here if(pRoot == null) return null; // 构建辅助栈 Stack<TreeNode> stack = new Stack<>(); // 根节点入栈 stack.add(pRoot); while(!stack.isEmpty()) { // 节点出栈 TreeNode node = stack.pop(); // 根节点的左右子树入栈 if(node.left != null) stack.add(node.left); if(node.right != null) stack.add(node.right); // 左右子树交换 TreeNode tmp = node.left; node.left = node.right; node.right = tmp; } return pRoot; } }
提示:
1.vin.length == pre.length
2.pre 和 vin 均无重复元素
3.vin出现的元素均出现在 pre里
4.只需要返回根结点,系统会自动输出整颗树做答案对比
数据范围:n≤2000,节点的值 −10000≤val≤10000
要求:空间复杂度 O(n),时间复杂度 O(n)
示例
示例1
输入:[1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6]
返回值:{1,2,3,4,#,5,6,#,7,#,#,8}
说明:返回根节点,系统会输出整颗二叉树对比结果,重建结果如题面图示
示例2
输入:[1],[1]
返回值:{1}
示例3
输入:[1,2,3,4,5,6,7],[3,2,4,1,6,5,7]
返回值:{1,2,5,3,4,6,7}
题解
Java代码实现:
public class Solution { public TreeNode reConstructBinaryTree(int [] pre,int [] in) { return dfs(0, 0, in.length - 1, pre, in); } public TreeNode dfs(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder) { if (preStart > preorder.length - 1 || inStart > inEnd) { return null; } //创建结点 TreeNode root = new TreeNode(preorder[preStart]); int index = 0; //找到当前节点root在中序遍历中的位置,然后再把数组分两半 for (int i = inStart; i <= inEnd; i++) { if (inorder[i] == root.val) { index = i; break; } } root.left = dfs(preStart + 1, inStart, index - 1, preorder, inorder); root.right = dfs(preStart + index - inStart + 1, index + 1, inEnd, preorder, inorder); return root; }
思路:二叉树的前序遍历:根左右;中序遍历:左根右。设置三个指针,一个是preStart,表示的是前序遍历开始的位置,一个是inStart,表示的是中序遍历开始的位置。一个是inEnd,表示的是中序遍历结束的位置,我们主要是对中序遍历的数组进行拆解
问题5:二叉搜索树与双向链表
原题:二叉搜索树与双向链表
描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
数据范围:输入二叉树的节点数 0≤n≤1000,二叉树中每个节点的值 0≤val≤1000
要求:空间复杂度O(1)(即在原树上操作),时间复杂度 O(n)
注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出
输入描述: 二叉树的根节点
返回值描述: 双向链表的其中一个头节点。
示例
示例1
输入:{10,6,14,4,8,12,16}
返回值:From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4;
说明:输入题面图中二叉树,输出的时候将双向链表的头节点返回即可。
示例2
输入:{5,4,#,3,#,2,#,1}
返回值:From left to right are:1,2,3,4,5;From right to left are:5,4,3,2,1;
题解
Java代码实现:
public class Solution { TreeNode pre=null; TreeNode root=null; public TreeNode Convert(TreeNode pRootOfTree) { if (pRootOfTree==null) return null; // 递归遍历左子树 Convert(pRootOfTree.left); // 判断特殊情况 if (root==null){ root=pRootOfTree; } // 修改遍历的结点为双向链表 if (pre!= null){ pRootOfTree.left=pre; pre.right=pRootOfTree; } // 更新 pre pre=pRootOfTree; // 递归遍历右子树 Convert(pRootOfTree.right); return root; } }