1.判断两棵树是否相同
思路:可以采用递归的方法,首先判断根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别递归判断两个二叉树的左树以及右树是否相同。
代码:
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null&&q==null){
return true;
}
if(p!=null&&q==null||p==null&&q!=null){
return false;
}
//p!=null&&q!=null
if(p.val!=q.val){
return false;
}
return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
2.判断一棵树是不是另一棵树的子树
思路:同样采用递归的思路,可以先判断两棵树是不是同一颗数,如果是,则返回true,如果不是,可递归判断其左树、右树是否与该子树是同一棵树。
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root==null||subRoot==null){
return false;
}
if(isSameTree(root,subRoot)){
return true;
}
return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);
}
3.求二叉树最大深度
思路:其实就是求树的高度,数的高度可以看做是左树或右树的最大值加1,通过递归即可实现
int getHeight(TreeNode root){
if(root==null){
return 0;
}
int leftH=getHeight(root.left);
int leftR=getHeight(root.right);
return leftH-leftR>0?leftH+1:leftR+1;
}
4.判断一颗树是否是平衡二叉树
思路:平衡二叉树是指每颗子树左右高度差不能超过1,并且其子树也应为平衡二叉树
方法1
//判断一棵树是不是平衡二叉树,时间复杂度为O(N^2)
public boolean isBalanced(TreeNode root) {
if(root==null){
return true;
}
//getHeight在上面写过了
int leftH=getHeight(root.left);
int leftR=getHeight(root.right);
return Math.abs(leftH-leftR)<=1&&isBalanced(root.left)&&isBalanced(root.right);
}
方法2
//判断一棵树是不是平衡二叉树,时间复杂度为O(N)
public boolean isBalanced2(TreeNode root) {
return getHeight2(root)>=0;
}
// 获取二叉树的高度
int getHeight2(TreeNode root){
if(root==null){
return 0;
}
int leftH=getHeight2(root.left);
int leftR=getHeight2(root.right);
if(leftH>=0&&leftR>=0&&Math.abs(leftH-leftR)<=1){
return Math.max(leftH,leftR)+1;
}else{
return -1;
}
}
5.对称二叉树
思路:对称二叉树,其左子树的左树与右子树的右树,左子树的右树与右子树的左树也都要对称
//对称二叉树
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return isSymmetricchild(root.left,root.right);
}
public boolean isSymmetricchild(TreeNode leftTree,TreeNode rightTree) {
if(leftTree!=null&&rightTree==null||leftTree==null&&rightTree!=null){
return false;
}
if(leftTree==null&&rightTree==null){
return true;
}
if(leftTree.val!=rightTree.val){
return false;
}
return isSymmetricchild(leftTree.left,rightTree.right)&&isSymmetricchild(leftTree.right,rightTree.left);
}
6.二叉树的构建及遍历
import java.util.Scanner;
class TreeNode {
public char val;
public TreeNode left;
public TreeNode right;
public TreeNode(char val) {
this.val = val;
}
}
public class Main {
public static int i=0;
public static TreeNode creatTree(String str) {
TreeNode root=null;
if(str.charAt(i)!='#'){
root=new TreeNode(str.charAt(i));
i++;
root.left=creatTree(str);
root.right=creatTree(str);
}else{
i++;
}
return root;
}
//中序遍历
public static void inOrder(TreeNode root){
if(root==null){
return;
}
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextLine()) {
String str = in.nextLine();
TreeNode root =creatTree(str);
inOrder(root);
}
}
}
7.二叉树的分层遍历
思路:可以借助队列来存储,当根节点不为空的时候,将根节点存入队列,当队列不为空的时候,弹出队头元素并打印,判断该节点的左孩子右孩子是否为空,不为空的话入队,如此循环至队列为空,即可实现分层遍历。
//层序遍历
void leveOrder(TreeNode root){
Queue<TreeNode> queue=new LinkedList<>();
if(root!=null){
queue.offer(root);
}
while (!queue.isEmpty()){
TreeNode cur=queue.poll();
System.out.print(cur.val+" ");
if(cur.left!=null){
queue.offer(cur.left);
}
if(cur.right!=null){
queue.offer(cur.right);
}
}
}
//分层遍历,以List的方式返回
public List<List<Character>> levelOrder2(TreeNode root) {
List<List<Character>> ret=new ArrayList<>();
if(root==null){
return ret;
}
//借助队列来存取
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
List<Character> curRow=new ArrayList<>();//存入当前行
int size=queue.size();//获取当前队列元素个数
while (size!=0){
TreeNode cur=queue.poll();//弹出队头元素,放入当前行中,同时判断如果该结点有孩子,存入队列
curRow.add(cur.val);
if(cur.left!=null){
queue.offer(cur.left);
}
if(cur.right!=null){
queue.offer(cur.right);
}
size--;
}
ret.add(curRow);
}
return ret;
}
8.给定一个二叉树,找到该树中两个指定结点的最近公共结点
思路:假设p和q有一个是根节点或者不在同一颗子树中,那么直接返回根节点就是这两个结点的最近公共结点;如果p和q在同一颗子树中,那么层级小的为最近公共结点
//给定一个二叉树,找到两个指定结点的最近公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
if(root==p||root==q){
return root;
}
TreeNode left=lowestCommonAncestor(root.left,p,q);
TreeNode right=lowestCommonAncestor(root.right,p,q);
if(left!=null&&right!=null){
return root;
}
if(left!=null){
return left;
}
if(right!=null){
return right;
}
return null;
}
9.二叉树搜索树转换成排序双向链表
思路:实现排序可以通过中序遍历做到,那我们再同时修改结点的指向就可以实现双向链表,使用一个全局变量prev保存前一个结点,pcur是指当前结点
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
二叉树搜索树转换成排序双向链表
*/
public class Solution {
public TreeNode prev=null;
//中序遍历
public void Convertchild(TreeNode pcur) {
if(pcur==null){
return;
}
Convertchild(pcur.left);
pcur.left=prev;//给当前的pcur数字赋左边的数据,prev保存前一个pcur
if(prev!=null){//prev==null说明是在叶子结点(该题的第一个结点),如果prev.right就会空指针异常
prev.right=pcur;//将当前数据赋给前一个数据的右边
}
prev=pcur;//修改完指向后将当前结点保存为prev
Convertchild(pcur.right);
}
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null){
return null;
}
//修改结构
Convertchild(pRootOfTree);
TreeNode head=pRootOfTree;
while(head.left!=null){
head=head.left;
}
return head;
}
}
10.根据一颗树的前序遍历和中序遍历构造二叉树
思路:前序遍历的第一个结点一定是根节点,拿到根节点后去中序遍历数组中找到相应结点,则该结点之前都是左子树元素,之后都是右子树元素,左子树元素在前序遍历中对应的第一个结点则为左子树的根节点,右子树元素在前序遍历中对应的第一个结点则为由子树的根节点,循环查找即可得出二叉树
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public int preindex=0;
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTreechild(preorder,inorder,0,inorder.length-1);
}
public TreeNode buildTreechild(int[] preorder,int[] inorder,int ibegin,int inend) {
if(ibegin>inend){
return null;
}
TreeNode root=new TreeNode(preorder[preindex]);
int rootindex=findindex(inorder,preorder[preindex],ibegin,inend);
preindex++;
root.left=buildTreechild(preorder,inorder,ibegin,rootindex-1);
root.right=buildTreechild(preorder,inorder,rootindex+1,inend);
return root;
}
public int findindex(int[] inorder,int key,int ibegin,int inend){
for(int i=ibegin;i<=inend;i++){
if(inorder[i]==key){
return i;
}
}
return -1;
}
}
11.根据一棵树的中序遍历与后序遍历构造二叉树
思路:后序遍历的最后一个结点一定是根节点,拿到根节点后去中序遍历数组中找到相应结点,则该结点之前都是左子树元素,之后都是右子树元素,左子树元素在后序遍历中对应的最后一个结点则为左子树的根节点,右子树元素在后序遍历中对应的最后一个结点则为由子树的根节点,循环查找即可得出二叉树
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public int postindex=0;
public TreeNode buildTree(int[] inorder, int[] postorder) {
postindex=postorder.length-1;
return buildTreechild(postorder,inorder,0,inorder.length-1);
}
public TreeNode buildTreechild(int[] postorder,int[] inorder, int ibegin,int inend) {
if(ibegin>inend){
return null;
}
TreeNode root=new TreeNode(postorder[postindex]);
int rootindex=findindex(inorder,postorder[postindex],ibegin,inend);
postindex--;
root.right=buildTreechild(postorder,inorder,rootindex+1,inend);
root.left=buildTreechild(postorder,inorder,ibegin,rootindex-1);
return root;
}
public int findindex(int[] inorder,int key,int ibegin,int inend){
for(int i=ibegin;i<=inend;i++){
if(inorder[i]==key){
return i;
}
}
return -1;
}
}
12.二叉树构建字符串
思路:
-
如果当前节点有两个孩子,那我们在递归时,需要在两个孩子的结果外都加上一层括号;
-
如果当前节点没有孩子,那我们不需要在节点后面加上任何括号;
- 如果当前节点只有左孩子,那我们在递归时,只需要在左孩子的结果外加上一层括号,而不需要给右孩子加上任何括号;
-
如果当前节点只有右孩子,那我们在递归时,需要先加上一层空的括号 ‘()’ 表示左孩子为空,再对右孩子进行递归,并在结果外加上一层括号。
//二叉树创建字符串
public String tree2str(TreeNode root) {
StringBuilder sb=new StringBuilder();
if(root==null){
return new String(sb);
}
tree2strchild(root,sb);
return new String(sb);
}
public void tree2strchild(TreeNode t, StringBuilder sb) {
if(t==null){
return ;
}
sb.append(t.val);
if(t.left!=null){
sb.append("(");
tree2strchild(t.left,sb);
sb.append(")");
}else{
if(t.right==null){
return;
}else{
sb.append("()");//通过判断右为不为空来判断左边是直接返回还是加()
}
}
if(t.right!=null){
sb.append("(");
tree2strchild(t.right,sb);
sb.append(")");
}else{
return;
}
}
13.二叉树前序遍历
//递归实现前序遍历
void preOrder(TreeNode root){
if(root==null){
return;
}
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
//非递归实现前序遍历
public List<Character> preorderTraversal(TreeNode root){
List<Character> list=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
TreeNode cur=root;
while (cur!=null||!stack.empty()) {
while (cur != null) {
stack.push(cur);
list.add(cur.val);
cur = cur.left;
}
TreeNode top = stack.pop();
cur = top.right;
}
return list;
}
14.二叉树中序遍历
//非递归实现中序遍历
public List<Character> inorderTraversal(TreeNode root) {
List<Character> list=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
TreeNode cur=root;
while (cur!=null||!stack.empty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.pop();
list.add(top.val);
cur=top.right;
}
return list;
}
//递归实现中序遍历
void inOrder(TreeNode root){
if(root==null){
return;
}
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
15.二叉树后序遍历
//非递归实现后序遍历
public List<Character> postorderTraversal(TreeNode root) {
List<Character> list=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
TreeNode cur=root;
TreeNode prev=null;
while (cur!=null||!stack.empty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.peek();
if(top.right==null||top.right==prev){
list.add(top.val);
prev=top;
stack.pop();
}else{
cur=top.right;
}
}
return list;
}
//递归实现后序遍历
void postOrder(TreeNode root){
if(root==null){
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val+" ");
}