剑指offer---递归刷题&&&二叉树遍历

递归1:树的子结构

题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

解题思路
首先要先在A中找到B的根节点,然后从根节点开始一一比对左右子树是否相等。

public class Solution{
	public boolean HasSubTree(TreeNode root1,TreeNode root2)
	{
		if(root2==null || root1==null)
			return false;
		if(root1.val == root2.val)
		{
			//如果找到B的根节点,则需要判断左右节点
			if(judgeSub(root1,root2))
				return true;		
		}
		return HasSubTree(root1.left,root2) || HasSubTree(root1.right,root2);
	}
	
	public boolean judgeSub(TreeNode root1,TreeNode root2)
	{
		if(root2 == null)
			return true;
		if(root1 == null)
			return false;
		if(root1.val == root2.val)
		{
			return judgeSub(root1.left,root2.left)&&judgeSub(root1.right,root2.right);
		}
		return false;
	}
}

二叉树的镜像

题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
在这里插入图片描述

public class Solution {
    public void Mirror(TreeNode root) {
        if(root == null)
            return;
        TreeNode temp = null;
        temp = root.left;
        root.left = root.right;
        root.right = temp;
        Mirror(root.left);
        Mirror(root.right);
    }
}

从上往下打印二叉树—层级遍历(队列)

题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

解题思路
本题实际上就是二叉树的层次遍历,深度遍历可以用递归或者栈,而层次遍历很明显应该使用队列。同样我们可以通过一个例子来分析得到规律:每次打印一个结点时,如果该结点有子结点,则将子结点放到队列的末尾,接下来取出队列的头重复前面的打印动作,直到队列中所有的结点都打印完毕。
在这里插入图片描述
在这里插入图片描述

//遍历二叉树
import java.util.Queue;
import java.util.LinkedList;
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<Integer> list = new ArrayList<>();
        if(root==null)
            return list;
        queue.offer(root);
        while(!queue.isEmpty())
        {
            //打印队头,同时将队头的左右子节点加到队尾
            TreeNode cur = queue.poll();
            list.add(cur.val);
            if(cur.left!=null)
                queue.offer(cur.left);
            if(cur.right!=null)
                queue.offer(cur.right);
            
        }
        return list;
    }
}

二叉树的后序遍历(递归)

题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。

解题思路
后序遍历的最后一个元素为根节点,左子树较根节点小,右子树较根节点大,由此可判断出左右子树的分界点。并需要判断分界点右侧的右子树元素是否都小于根节点,若不满足,也不是后序遍历。
还是按上面的方法确定对应的子树的结构,这是一个递归的过程。如果递归过程中发现其右子序列中有值小于根值,那么这不是一个后序序列。

public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence==null||sequence.length==0)
        	return false;
        if(sequence.length==1)
        	return true;
        return help(sequence,0,sequence.length-1);
    }
    public boolean help(int[] arr,int start,int end)
    {
		if(start>=end)
			return true;
		int leftindex = start;
		while(arr[leftindex]<arr[end])
			leftindex++;
		int rightindex = leftindex;
		while(arr[rightindex]>arr[end])
			rightindex++;
		return (rightindex==end)&&help(arr,start,leftindex-1)&&help(arr,leftindex,end-1);
	}
}

二叉树中和为某一值的路径

题目描述
输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

解题思路:
这是一道DFS题目,也可以看做是先序遍历的题目 ,在二叉树中,dfs就相当于先序遍历
首先,采用一种“减法”思想,当检查一棵树从根到叶子节点形成的路径的和是否为target时,先将当前根节点的值 root.val 加入path, 然后检查它的左子树(若非空),看从左子树的根到叶子节点形成的路径的和是否为 target - root.val (递归), 然后同样的道理去递归检查右子树(若非空),这便是大致的思路。
但这道题麻烦的一点是,它要求记录下所有符合标准的路径,这便用到了dfs的特性。
但又来了一件麻烦事,先序遍历便是先左后右。检查完左子树后,会对path就行修改,再去查找右子树,如何将path恢复到之前未进行左子树检查的状态?

比较好的做法是将path设为全局的,然后dfs的过程便是先序遍历的过程,一旦遍历到叶子结点,便将path最后的节点移除掉,这样在递归一层一层进行的时候将值添加进path,在递归返回的过程中将path最末尾的元素一个一个移除。这样便依靠递归的特性完成了路径的恢复。

例如对于树 10,5,12,5,7,#,#,#,#,#,#,#,#(层序遍历),path变化过程为 10,5,5 》》 10,5 》》 10,5,7 》》10,5 》》10 》》10,12 》》10 》》 null

因为最终遍历到叶子结点时,若发现符合规定的路径,是把path加入到结果集中,因为java中添加的是引用,而path是不断变化的,所以我们要新new一个当前路径的副本出来,防止添加进去的path都是相同的(最终path的状态)。

public class Solution {
    ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    ArrayList<Integer> path = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        if(root==null)
            return res;
        help(root,target);
        return res;
    }
    public void help(TreeNode node,int target)
    {
        path.add(node.val);
        if(node.val == target && node.left==null && node.right == null)
        {
            //当到达叶子节点并且和等于目标数,将path加入res
            res.add(new ArrayList(path));
        }
        if(node.left!=null)
        {
            //左子树不为空,左子树递归
            help(node.left,target-node.val);
        }
        if(node.right!=null)
            help(node.right,target-node.val);
        path.remove(path.size()-1);
        return;
    }
}

二叉搜索树与双向链表

题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
在这里插入图片描述
题目解析:

先将节点按照中序遍历的顺序加入到ArrayList中,再依次遍历数组中元素进行链表的组建。

import java.util.ArrayList;
public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree==null)
            return null;
        ArrayList<TreeNode> list = new ArrayList<>();
        InOrder(pRootOfTree,list);
        return Convert(list);
    }
    public void InOrder(TreeNode node,ArrayList<TreeNode> list)
    {
        //先按照中序遍历顺序将节点放入list
        if(node.left!=null)
            InOrder(node.left,list);
        list.add(node);
        if(node.right != null)
            InOrder(node.right,list);
    }
    public TreeNode Convert(ArrayList<TreeNode> list)
    {
        for(int i=0;i<list.size()-1;i++)
        {
            list.get(i).right = list.get(i+1);
            list.get(i+1).left = list.get(i);
        }
        return list.get(0);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值