输入一棵二叉树,判断该二叉树是否是平衡二叉树。

平衡二叉树的左右子树也是平衡二叉树,那么所谓平衡就是左右子树的高度差不超过1.
平衡二叉树:平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
题目:输入一棵二叉树,判断该二叉树是否是平衡二叉树。
思路:利用求深度的方法,依次遍历左右子树,用他们的深度相减,结果大于1的,返回-1;否则返回树的深度

解题思路有两种,只遍历一次的方法最优。

重复遍历多次:

在遍历树的每个结点的时候,调用函数TreeDepth得到它的左右子树的深度。如果每个结点的左右子树的深度相差都不超过1,则这是一颗平衡的二叉树。这种方法的缺点是,首先判断根结点是不是平衡的,需要使用TreeDepth获得左右子树的深度,然后还需要继续判断子树是不是平衡的,还是需要使用TreeDepth获得子树的左右子树的深度,这样就导致了大量的重复遍历。

只遍历一次:

重复遍历会影响算法的性能,所以很有必要掌握不需要重复遍历的方法。如果我们用后序遍历的方式遍历二叉树的每一个结点,在遍历到一个结点之前我们就已经遍历了它的左右子树。只要在遍历每个结点的时候记录它的深度(某一结点的深度等于它到叶结点的路径的长度),我们就可以一边遍历一边判断每个结点是不是平衡的。

class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        int depth = 0;//
        return IsBalanced(pRoot, &depth);//返回一个布尔值
    }
private:
    int IsBalanced(TreeNode* pRoot, int* depth){
        if(pRoot == NULL){
            *depth = 0;
            return true;//空树是的。后续遍历时,遍历到一个节点,其左右子树已经遍历  依次自底向上判断,每个节点只需要遍历一次
        }
        int left, right;
        if(IsBalanced(pRoot->left, &left) && IsBalanced(pRoot->right, &right)){
            int diff = left - right;//差值
            if(diff <= 1 && diff >= -1){//绝对值不超过1,depth保存每一步遍历的深度,同时返回该节点是否是平衡的
                *depth = 1 + (left > right ? left : right);//遍历过程中求子树高度,判断是否平衡
                return true;//必须左边和右边都满足平衡,并且差值小于1才是真,循环遍历,从下面开始,记录这个节点的深度
            }
        }
        return false;//左边或者右边不平衡就一定是假,如果在底层发现不平衡了,就直接一路返回。
//自下往上,算法复杂度O(N)
    }
};

 

给定一个二叉树的前序遍历和中序遍历的序列,输出对应这个二叉树的后续遍历序列。

输入描述:

输入为一行。 两个字符串,分别表示二叉树的前序遍历和中序遍历结果,用空格分隔。保证数据合法


 

输出描述:

对应输出后序遍历序列

示例1

输入

ABDEC DBEAC

输出

DEBCA
import sys
# 定义节点
class TreeNode(object):
    def __init__(self,val,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
# 重建二叉树
def rebuild(pre,pos):
    if pre =='':
        return 
    val = pre[0]
    index = pos.index(val)
    root = TreeNode(val)
    root.left = rebuild(pre[1:1+index],pos[:index])
    root.right = rebuild(pre[1+index:],pos[index+1:])
    return root
# 后续遍历第归实现
def posorder(root):
    if root is None:
        return
    posorder(root.left)
    posorder(root.right)
    print(root.val,end='')
if __name__ =="__main__":
    line = sys.stdin.readline().strip()
    pre,pos = line.split()
    root = rebuild(pre,pos)
    res = posorder(root)


import java.util.Scanner;
import java.util.Arrays;
 
// 自定义树节点
class TreeNode {
    TreeNode left;
    TreeNode right;
    char val;
    public TreeNode(char x) {
        val = x;
    }
}
 
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str = sc.nextLine();
            String[] s = str.split(" ");
            char[] pre = s[0].toCharArray();    // 前序遍历的序列
            char[] in = s[1].toCharArray();    // 中序遍历的序列
            TreeNode tree = constructTree(pre, in); // 构建二叉树
            printPost(tree); // 打印后序遍历序列
        }
        sc.close();
    }
 
    // 根据前序遍历序列和中序遍历序列构建二叉树
    private static TreeNode constructTree(char[] pre, char[] in) {
        if (pre.length == 0 || in.length == 0)
            return null;
        char rootVal = pre[0];
        TreeNode root = new TreeNode(rootVal);    // 先构建一个根节点
        for (int i = 0; i < in.length; ++i) {
            if (in[i] == rootVal) {
                root.left = constructTree(Arrays.copyOfRange(pre,1,i+1),
                                         Arrays.copyOfRange(in,0,i));
                root.right = constructTree(Arrays.copyOfRange(pre,i+1,pre.length),
                                          Arrays.copyOfRange(in,i+1,in.length));
                break;
            }
        }
        return root;
    }
     
    // 打印后序遍历序列
    private static void printPost(TreeNode tree) {
        if (tree == null) {
            return;
        } else {
            printPost(tree.left);
            printPost(tree.right);
            System.out.print(tree.val);
        }
    }
}

给满出二叉树,编写算法将其转化为求和树

什么是求和树:二叉树的求和树, 是一颗同样结构的二叉树,其树中的每个节点将包含原始树中的左子树和右子树的和。

二叉树:
                  10
               /      \
             -2        6
           /   \      /  \ 
          8    -4    7    5

求和树:
                 20(4-2+12+6)
               /      \
           4(8-4)      12(7+5)
            /   \      /  \ 
          0      0    0    0
 

二叉树给出前序和中序输入,求和树要求中序输出;

所有处理数据不会大于int;

 

输入描述:

2行整数,第1行表示二叉树的前序遍历,第2行表示二叉树的中序遍历,以空格分割

输出描述:

1行整数,表示求和树的中序遍历,以空格分割

示例1

输入

复制

10 -2 8 -4 6 7 5 8 -2 -4 10 7 6 5

输出

复制

0 4 0 20 0 12 0



因为是满二叉树,其实结果跟前序遍历数组无关,只和中序遍历数组有关,并且中序数组一定是奇数个,结果索引为偶数的一定为0,索引为奇数的值是中序遍历数组其他值之和(不包括自己),使用二分法找到根节点,然后计算子树之和,不用还原二叉树

 

本题有如下规律:

求和树的根节点 = 除本身外原二叉树所有子节点之和,

本题中根节点为中序遍历数组中正中间项(满二叉树)

递归求得左右子树,直到子树节点个数为1返回[0]。

需要考虑根节点在两侧的情况,树节点个数为0时,返回空[]

mid = len(d) // 2  # 满二叉树根节点即正中间数值,前序遍历数组本题中用不到,



var line1 = readline().split(" ").map(Number)//第一行转换成数字
var line2 = readline().split(" ").map(Number)
/* 前中序遍历的数组恢复二叉树 */
function ArrayToTreeNode(pre, ino) {
    if(pre.length === 0 || !pre) {
        return null//初始
    }
    var root = {
        val: pre[0],
        left:null,
        right:null,
        add: 0//构造跟节点
    }
    var index = ino.indexOf(pre[0])//找到跟节点的下标
    root.left = ArrayToTreeNode(pre.slice(1, index+1), ino.slice(0, index))//前序后面的是左边,截取数组,中序就是从0到跟节点。
    root.right = ArrayToTreeNode(pre.slice(index + 1), ino.slice(index + 1))//一直截取到最后//这里是重建了二叉树
    if (root.left != null) root.add = root.add + root.left.val + root.left.add
    if (root.right != null) root.add = root.add + root.right.val + root.right.add
    return root//重建求和的二叉树
}
 
var arr = []
var bt = ArrayToTreeNode(line1, line2)
/* 非递归且通用的中序遍历方法 */
var inorderTraversal2 = function(root) {
    let res = [];
    let stack = [];
    const [W , G] = [0, 1];
    stack.push({c:W, node:root});
    while(stack.length){
        let c,n;
        let curr_n = stack.pop();
        c = curr_n.c;
        n = curr_n.node;
        if(!n){
            continue;
        }
        if(c == W){
            stack.push({c:W, node:n.right})
            stack.push({c:G, node:n})
            stack.push({c:W, node:n.left})
        }
        else{
            res.push(n.add)
        }
    }
    return res;
};
arr = inorderTraversal2(bt).join(' ')
print(arr);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值