zoukankan      html  css  js  c++  java
  • 【剑指offer】算法题07.重建二叉树(C++)

    输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
    
    例如,给出
    前序遍历 preorder = [3,9,20,15,7]
    中序遍历 inorder = [9,3,15,20,7]
    返回如下的二叉树:
    
        3
       / 
      9  20
        /  
       15   7
     
    【限制】
    0 <= 节点个数 <= 5000

    【解题思路】

    前序遍历的特点【根节点|左子树|右子树】

    中序遍历的特点【左子树|根节点|右子树】

    根据以上特点,可以按顺序完成以下工作:

    • 确定根节点root的值,等于前序遍历的第一个元素。
    • 在中序遍历中找到root值的索引位置,确定左子树和右子树的元素个数以及中序遍历。
    • 根据上一步确定的元素个数,在前序遍历中确定左子树和右子树的前序遍历。
    • 通过同样的方法对左(右)子树进行划分,每轮可确认三个节点的关系 。此递推性质让我们联想到用 递归方法 处理。

    线性遍历了每一个节点,时间复杂度为O(n),开辟了新的hash表来存储中序遍历,因此空间复杂度为O(n)。

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        //使用一个全局的hash表来存放中序遍历中的{元素,元素下标}
        unordered_map<int,int> bp;
        TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
            //当前序或者中序数组为空,或者他们的长度不一致时,返回空
            if(preorder.empty()||inorder.empty()||preorder.size()!=inorder.size())
                return NULL;
            int n=preorder.size()-1;
            for(int i=0;i<=n;i++){ //依次存入hash表中
                bp.insert({inorder[i],i});
            }
            return construct(preorder,0,n,inorder,0,n);
        }
    /**
     * @param pre  前序遍历
     * @param pb   前序遍历的开始位置
     * @param pe   前序遍历的结束位置
     * @param ino  中序遍历
     * @param ib    中序遍历的开始位置
     * @param ie    中序遍历的结束位置
     */
        TreeNode* construct(vector<int> pre, int pb, int pe, vector<int> ino, int ib, int ie){
            if(pb>pe)  //如果开始位置大于结束位置,说明没有需要处理的元素了
                return NULL;
            int key=pre[pb];
            if(bp.find(key)==bp.end())
                return NULL;
            int index=bp[key];  //确定根节点在中序遍历中的位置,返回其下标
            TreeNode* node = new TreeNode(key);
            //则左子树的元素个数为index-ib,递归如下
            node->left=construct(pre,pb+1,pb+index-ib,ino,ib,index-1);
            node->right=construct(pre,pb+index-ib+1,pe,ino,index+1,ie);
            return node;
        }
    };

    此外,也可以不使用hash表,但需要每次遍历一遍新的中序数组来确定根节点的索引,如下

    TreeNode* construct(vector<int> pre, int pb, int pe, vector<int> ino, int ib, int ie){
            if(pb>pe)
                return NULL;
            int key=pre[pb];
            int index=ib;
            //仅仅此处和上面不同,通过遍历的方式来找到index,效率不如hash表高,只节省了空间
            while(index<=ie && ino[index]!=key)
                index++;
            TreeNode* node = new TreeNode(key);
            node->left=construct(pre,pb+1,pb+index-ib,ino,ib,index-1);
            node->right=construct(pre,pb+index-ib+1,pe,ino,index+1,ie);
            return node;
        }
    };

    相关总结

    1. 什么是C++STL: unordered_map ?

      unordered_map是C++中的一个关联容器,内部采用的是hash表结构,拥有快速检索的功能。其特性如下:

    • 关联性:通过key去检索value,而不是通过绝对地址(和顺序容器不同)
    • 无序性:使用hash表存储,内部无序
    • Map : 每个值对应一个键值
    • 键唯一性:不存在两个元素的键一样
    • 动态内存管理:使用内存管理模型来动态管理所需要的内存空间

      有关unordered_map的详细操作可参考https://blog.csdn.net/lizhengze1117/article/details/96728468

    2. map和unordered_map的区别。

      C++中map提供的是一种键值对容器,键不能有重复的,值可以重复,map使用键来存储数据,系统会根据键来自动将数据排序。map的value_type是pair<const key_type, mapped_type>,所以map迭代器只能改变关键字映射的值(mapped_type),不能修改关键字。

      unordered_map的用法和map是一样的,提供了 insert,size,count等操作,并且里面的元素也是以pair类型来存贮的。就外部使用来说却是一致的,但它俩的底层实现完全不同。

    • map: map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树(又名二叉查找树、二叉排序树,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)存储的,使用中序遍历可将键值按照从小到大遍历出来。
    • unordered_map: unordered_map内部实现了一个哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。因此,其元素的排列顺序是无序的。
  • 相关阅读:
    Solaris下批量kill掉oracle的session
    我写blog的方式变迁
    filezilla ftp client在win7 下获取ftp目录信息出错解决方法
    GNU System Monitor编译问题
    在vmware的Solaris虚拟机中安装vmtool
    关于golden gate director client的一点点使用总结
    测试 乱弹
    ORM的世界 (再补充)
    Yahoo Konfabulator
    轻量容器和注射依赖 的自实现
  • 原文地址:https://www.cnblogs.com/ziziQ/p/12517668.html
Copyright © 2011-2022 走看看