剑指offer之二叉树总结

会用递归了二叉树的问题就会一大半了...

一.用递归求解

对于要利用二叉树的规律的题都可以利用它的左节点也是其左子树的根节点的特性来递归求解。可以说那种参数有根节点的题一般都可以用递归来解决,来看看《剑指offer》中可用递归解决的题

1.根据前序遍历的性质,第一个元素必然就是root,那么下面的工作就是如何确定root的左右子树的范围。根据中序遍历的性质,root元素前面都是root的左子树,后面都是root的右子树。那么我们只要找到中序遍历中root的位置,就可以确定好左右子树的范围

struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
    int inlen=in.size();
    if(inlen==0)
        return NULL;
    vector<int> left_pre,right_pre,left_in,right_in;
    TreeNode* head=new TreeNode(pre[0]);
    int gen=0;
    for(int i=0;i<inlen;i++)
    {
        if (in[i]==pre[0])
        {
            gen=i;

            break;
        }
    }
    for(int i=0;i<gen;i++)
    {
        left_in.push_back(in[i]);

        left_pre.push_back(pre[i+1]);
    }
    for(int i=gen+1;i<inlen;i++)
    {
        right_in.push_back(in[i]);
        right_pre.push_back(pre[i]);
    }
    head->left=reConstructBinaryTree(left_pre,left_in);
    head->right=reConstructBinaryTree(right_pre,right_in);
    return head;

}

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

bool isSubtree(TreeNode* pRootA, TreeNode* pRootB) {
    if (pRootB == NULL) return true;
    if (pRootA == NULL) return false;
    if (pRootB->val == pRootA->val) {
        return isSubtree(pRootA->left, pRootB->left)
               && isSubtree(pRootA->right, pRootB->right);
    } else return false;
}
bool HasSubtree(TreeNode* pRootA, TreeNode* pRootB)
{
    if (pRootA == NULL || pRootB == NULL) return false;
    return isSubtree(pRootA, pRootB) ||
           HasSubtree(pRootA->left, pRootB) ||
           HasSubtree(pRootA->right, pRootB);
}

首先对于A,B当前节点,如果相等那么就接着判断他们的左子树上的节点是否相等以及右子树上的节点是否相等

3.操作给定的二叉树,将其变换为源二叉树的镜像

void Mirror(TreeNode *pRoot) {
    if(pRoot==NULL){
        return;
    }
    TreeNode *tmp = pRoot->left;
    pRoot->left = pRoot->right;
    pRoot->right = tmp;
    Mirror(pRoot->left);
    Mirror(pRoot->right);
}

4.输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

bool judge(vector<int>& a){
    int size = a.size();
    if(0==size)return false;

    int i = 0;
    while(--size)
    {
        while(a[i++]<a[size]);
        while(a[i++]>a[size]);
        if(i<size)return false;
        i=0;
    }
    return true;

}

后序遍历出的数组元素特点是对于每个点的前面所有元素,都是一部分小于它然后又是大于它

5.输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

class Solution {
public:
    vector<vector<int>> res;
    int ex;
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        this->ex = expectNumber;
        if(root == NULL)
            return res;
        TreeNode* temp = root;
        vector<int>s;
        int sum = 0;
        BSD(root,s,sum);
        return this->res;
    }
    void BSD(TreeNode* root,vector<int>s,int sum){
        sum += root->val;
        s.push_back(root->val);
        if(root->left == NULL && root->right == NULL){

            if(sum == ex)
                res.push_back(s);
            sum = 0;
            while(!s.empty()) s.pop_back();
            return;
        }

        if(root->left != NULL) BSD(root->left,s,sum);
        if(root->right != NULL) BSD(root->right,s,sum);
    }
};

6.输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if( pRootOfTree == NULL)
            return NULL;
        TreeNode* root = pRootOfTree;
        TreeNode* p = pRootOfTree;
        TreeNode* pre = pRootOfTree;
        stack<TreeNode*> ss;
        bool isroot = true;
        while(!ss.empty() || p != NULL){
            while(p != NULL){
                ss.push(p);
                p = p->left;
            }
            p = ss.top();
            ss.pop();
            if(isroot){
                root = p;
                pre = root;
                isroot = false;
            }else{
                pre->right = p;
                p->left = pre;
                pre =  p;
            }
            p = p->right;
        }
        return root;
    }
};

7.输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

int TreeDepth(TreeNode* pRoot)
{
    if(pRoot == NULL)
        return 0;
    int height = max(TreeDepth(pRoot->left),TreeDepth(pRoot->right))+1;
    return height;
}

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

class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot == NULL)
            return true;
        return getheight(pRoot) != -1;
    }
    int getheight(TreeNode* node){
        if(node == NULL)
            return 0;
        int left = getheight(node->left);
        if(left == -1)
            return -1;
        int right = getheight(node->right);
        if(right == -1)
            return -1;
        int cnt = abs(left-right) > 1?-1:1;
        return cnt + max(left,right);

    }
};

上面题思路其实都一样,掌握了递归对这些题还是很简单

还有是对某一节点的分析

9.给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode == NULL)
            return NULL;
        if(pNode->right == NULL){
            while(pNode->next != NULL){
                if(pNode->next->left == pNode)
                    return pNode->next;
                pNode = pNode->next;
            }
            return NULL;
        }

        else{
            TreeLinkNode* temp = pNode->right;
            while(temp->left != NULL){
                temp = temp->left;
            }
            return temp;
        }
    }
};

主要是分几种情况

右节点为空:当前节点是不是其父节点的左节点

(1)若是则后继节点为其父节点

(2)若不是就一直往上遍历直至找到为左节点的点

右节点不为空:再看右节点有无左节点

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值