构造数组的MaxTree

来源:互联网 发布:漫画下载软件大全 编辑:程序博客网 时间:2024/05/16 01:46

【题目】

对于一个没有重复元素的整数数组,请用其中元素构造一棵MaxTree,MaxTree定义为一棵二叉树,其中的节点与数组元素一一对应,同时对于MaxTree的每棵子树,它的根的元素值为子树的最大值。现有一建树方法,对于数组中的每个元素,其在树中的父亲为数组中它左边比它大的第一个数和右边比它大的第一个数中更小的一个。若两边都不存在比它大的数,那么它就是树根。请设计O(n)的算法实现这个方法。

给定一个无重复元素的数组A和它的大小n,请返回一个数组,其中每个元素为原数组中对应位置元素在树中的父亲节点的编号,若为根则值为-1。

测试样例:
[3,1,4,2],4
返回:[2,0,-1,2]

代码如下:

class MaxTree {public:    vector<int> buildMaxTree(vector<int> A, int n) {    assert((int)A.size() == n && n >= 0);        vector<int> res(A.size(), -1);        stack<int> st;for(int i=0; i<A.size(); ++i){            while(!st.empty() && A[st.top()] < A[i]){                if(res[st.top()] == -1 || A[res[st.top()]] > A[i])//之前没有大于它的 或者 左边有但我们要选择一个小的父亲                    res[st.top()] = i;                st.pop();            }            if(!st.empty())               res[i] = st.top();            st.push(i);        }        return res;    }};

这道题核心在于栈,一种解法是从左往右使用栈遍历一遍数组,统计每个数左边第一个比它大的值,再从右往左遍历一遍,统计每个比它小的值,然后两个值较小的那个就是父亲节点。


但是我采用的是只遍历一遍的方法,使用栈来保存父节点下标。

举例:【3,1,4,2】

首先初始化res为-1,这是有用的。从左向右遍历,第一次为空,0入栈。仅执行st.push(0),它左边没有比它大的数,此时res[0]仍为-1。

继续,A[1] = 1,由于栈不空,且由栈顶保存下标A[st.top()]=A[0]>A[1]=1,所以1入栈,res[1]=0。

继续,A[2]=4,栈不空,且A[2]>A[st.top()]=A[1]=1,所以进入循环。循环中如果栈顶下标所对应元素值比4小,都弹出。如果找到一个res[st.top()]==-1的点,由于是栈结构,只会和该元素位置前的元素比较过,说明该点目前并没有找到任何一个左边比它大的点,所以将该点的res[st.top()]直接赋为i,成为它的父节点。另外一种可能是,由于是栈结构,栈顶只可能之前选择了一个比它大的点是左边比它大的点,所以如果满足A[res[st.top()]]>A[i],说明当前点是左右第一个比它大的点较小的一个,我们选择当前点作为父节点,所以也要更新res[st.top()]=i。

继续循环,就会得出结果。


思路整体:

        // 循环处理每一个元素
        // 需要一个额外的栈来辅助获取两个阶段的最大值(两个阶段指左边最大值和右边最大值)
        // 每次判断一个元素分三种情况
        //  1. 栈为空,也就是初始状态,直接将元素下标入栈(此时该元素的父结点下标为默认值 -1)
        //  2. 栈不为空,同时即将进栈的元素比栈顶元素小,那么直接将元素进栈同时更新当前元素的
        //     父结点下标为i(设定父结点为左边第一个比该元素大的,右侧第一个比该元素大的第3步说明)
        //  3. 栈不为空,同时即将进栈的元素比栈顶元素小,那么需要将栈顶元素出栈,然后比较
        //     需要分情况:
        //     1) 栈顶元素对应父结点下标为null, 说明栈顶元素左侧没有最大值,此时需要更新
        //        栈顶元素对应父结点下标为当前进栈元素的下标 i,然后将栈顶元素pop 出栈
        //     2) 栈顶元素对应的父结点下标对应数组中元素比,i 位置对应数组元素大,由maxTree 的
        //        定义,我们必须保存左侧和右侧相对较小的那个作为最终结果,所以也更新元素下标为i
        //        然后将栈顶元素 pop 出栈
        //     3) 如果不在上面两种情况范围内,直接将栈顶元素出栈,然后继续循环执行 3 步骤


0 0
原创粉丝点击