Leetcode---剑指Offer题7---二叉树的遍历




剑指Offer-面试题7---二叉树的遍历

1、题目1

https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

利用递归,把前序和中序拆成更小的前序和中序。

struct TreeNode
{
    int mValue;
    TreeNode *mLeft;
    TreeNode *mRight;
    TreeNode(int v)
            : mValue(v), mLeft(nullptr), mRight(nullptr) {}
};


TreeNode* BuildTree(vector<int> pre,vector<int> vin)
{
    if(pre.size()==0 || vin.size()==0)
        return nullptr;

    //新建根节点
    TreeNode* headNode = new TreeNode(pre[0]);
    int root = 0;

    //在中序中找到根节点
    for(int i=0; i<vin.size(); i++)
    {
        if(vin[i] == pre[0])
        {
            root = i;
            break;
        }
    }

    //根节点左边区间的前序和中序
    vector<int> preLeft(pre.begin()+1,pre.begin()+root+1);
    vector<int> vinLeft(vin.begin(),vin.begin()+root);
    //根节点右边区间的前序和中序
    vector<int> preRight(pre.begin()+root+1,pre.end());
    vector<int> vinRight(vin.begin()+root+1,vin.end());

    //递归求所有节点
    headNode->mLeft = BuildTree(preLeft,vinLeft);
    headNode->mRight = BuildTree(preRight,vinRight);

    return headNode;
}

2、题目2

给定一个二叉树和其中一个节点,找出中序遍历序列的下一个节点。

这道题主要是找规律,找到了规律就好做了(我就没找到)。
规律1:如果此节点有右子节点,那么下一个节点为右子节点的最左边节点。
规律2:如果没有右子节点,且有父节点。找到一个父节点,直到有(父节点)为(父节点的父节点)的左子节点,就为这个父父节点。

struct TreeNode{
    TreeNode* mParent;
    TreeNode* mLeftNode;
    TreeNode* mRightNode;
    TreeNode(TreeNode* parent=nullptr,TreeNode* left=nullptr,TreeNode* right=nullptr):mParent(parent),mLeftNode(left),mRightNode(right){}
};

TreeNode* FindMidNextNode(TreeNode* node)
{
    if(node == nullptr)
        return nullptr;
    TreeNode* nextNode = nullptr;
    //如果有右子节点,那么下一个为右子节点的最左边节点
    if(node->mRightNode != nullptr){
        TreeNode* temp = node->mRightNode;
        while(temp->mLeftNode != nullptr)
            temp = temp->mLeftNode;
        nextNode = temp;
    }
    //如果没有右子节点,且有父节点
    //直到有(父节点)为(父节点的父节点)的左子节点,就为这个父父节点
    else if(node->mParent != nullptr){
        TreeNode* temp = node->mParent;
        while(temp->mParent != nullptr){
            if(temp->mParent->mLeftNode = temp){
                nextNode = temp->mParent;
            }
            temp = temp->mParent;
        }
    }

    return nextNode;
}

3、题目3!!!

有一棵二叉树,树上每个点标有权值,权值各不相同,请设计一个算法算出权值最大的叶节点到权值最小的叶节点的距离。二叉树每条边的距离为1,一个节点经过多少条边到达另一个节点为这两个节点之间的距离。
给定二叉树的根节点root,请返回所求距离。

我看大佬用的map算二进制编码,然后计算距离。
大佬们太秀了,好好学学

struct TreeNode{
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};

void GetCode(map<int,string>& treeMap,TreeNode* root,string s)
{
    if(root->left==nullptr && root->right==nullptr){
        //给出01编码
        treeMap[root->val] = s;
        return;
    }
    if(root->left!=nullptr){
        GetCode(treeMap,root->left,s+'0');
    }
    if(root->right!=nullptr){
        GetCode(treeMap,root->right,s+'1');
    }
}


int getDis(TreeNode* root)
{
    if(root == nullptr)
        return 0;

    map<int,string> treeMap;

    GetCode(treeMap,root,"");
	//利用迭代器获取开头结尾的值(map会自动排序)
    auto minNum = treeMap.begin();
    string s1 = minNum->second;
    auto maxNum = (--treeMap.end());
    string s2 = maxNum->second;

	//根据编码计算距离
    int i = 0,j = 0;
    while(i<s1.size() && j<s2.size() && s1[i] == s2[j]){
        i++;j++;
    }
    return s1.size() + s2.size() - i - j;
}

4、题目4!!!

给定一个二叉树的前序遍历和中序遍历的序列节点编号按单个空格分开。
依次输出 从左向右叶子节点 ,先序, 后序 遍历 。 节点编号按空格分开

这个我开始也不知道如何根据层序找规律,后来看提示说每次在中序数组中找第一个在层序数组中出现的节点的位置,左边即为左子树、右边即为右子树,递归。

#include <iostream>
#include <cstring>
#include <vector>

using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;

const int MAX_Length = 2500;

vector<int> layerVector;
vector<int> midVector;


///构建二叉树结点
struct TreeNode
{
    int mValue;
    TreeNode* mLeft;
    TreeNode* mRight;
    TreeNode(int c):mValue(c),mLeft(nullptr),mRight(nullptr){}
};

///构建数
TreeNode* BuildTree(int layerL,int layerR,int midL,int midR)
{
    if(layerL > layerR || midL > midR){
        return nullptr;
    }

    //在中序数组找到第一个在层序数组中出现的结点的位置
    int i,j;
    for(i=layerL;i<=layerR;i++){
        for(j=midL;j<=midR;j++){
            if(midVector[j] == layerVector[i]){
                break;
            }
        }
        //寻找中序下一个
        if(j<=midR)
            break;
    }
    //那么在中序数组这个范围内,j左边就为这个节点的左子树,j右边就为这个节点的右子树
    TreeNode* root = new TreeNode(midVector[j]);

    root->mLeft = BuildTree(i,layerR,midL,j-1);
    root->mRight = BuildTree(i,layerR,j+1,midR);

    return root;
}

///叶子节点
void LeafOrder(TreeNode* root)
{
    if(root == nullptr)
        return;
    if(root->mLeft==nullptr && root->mRight==nullptr)
        cout<<root->mValue<<" ";
    LeafOrder(root->mLeft);
    LeafOrder(root->mRight);
}

///先序
void PreOrder(TreeNode* root)
{
    if(root == nullptr)
        return;
    cout<<root->mValue<<" ";
    PreOrder(root->mLeft);
    PreOrder(root->mRight);
}

///后序
void PastOrder(TreeNode* root)
{
    if(root == nullptr)
        return;
    PastOrder(root->mLeft);
    PastOrder(root->mRight);
    cout<<root->mValue<<" ";
}

int main()
{
    //sscanf读取格式化的字符串中的数据
    int n;
    char* layer = new char[MAX_Length];
    cin.getline(layer,MAX_Length);
    //分割字符串
    char* temp = strtok(layer," ");
    while(temp != NULL){
		//把temp中的数据赋值给整型n
        sscanf(temp,"%d",&n);
        layerVector.push_back(n);
        temp = strtok(NULL," ");
    }

    char* mid = new char[MAX_Length];
    cin.getline(mid,MAX_Length);
    //分割字符串
    temp = strtok(mid," ");
    while(temp != NULL){
        sscanf(temp,"%d",&n);
        midVector.push_back(n);
        temp = strtok(NULL," ");
    }

    TreeNode* root = BuildTree(0,layerVector.size()-1,0,midVector.size()-1);

    LeafOrder(root);
    cout<<endl;
    PreOrder(root);
    cout<<endl;
    PastOrder(root);
    cout<<endl;

    return 0;
}

原文地址:https://www.cnblogs.com/Fflyqaq/p/12020605.html