整数划分问题(续)

本文介绍了一种通过栈操作实现的整数划分算法,该算法能够有效地输出整数的所有可能划分方式,并通过递归实现了深度和广度上的遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     在前面已经提到了整数划分的问题,在那个问题中,只需要求出整数划分的个数,如果要求将整数划分的所有划分方法也输出,该如何求解?如对于整数6,输出的结果就应该是:

     6

     5+1

     4+2   4+1+1

     3+3   3+2+1  3+1+1

     2+2+2 2+2+1+1 2+1+1+1+1

     1+1+1+1+1+1

    我们可以采用集合的思维去考虑,比如对于整数6,则初始集合相当于{1,1,1,1,1,1}

从1+1+1+1+1+1到2+1+1+1+1实际上就相当于我从左边那一堆{1,1,1,1,1,1}的集合中拿

两个1出来相加然后再把结果放回集合当中得到{2,1,1,1,1}.若这个时候我继续拿集合里面的两个

1相加再放回去就可以得到{2,2,1,1},同理再做同样的处理的话我们会得到{2,2,2}。

 

而对于第三层,我们可以先从{1,1,1,1,1,1}里面拿三个1,相加之后放回去得到{3,1,1,1},对于

{3,1,1,1}来说,剩下的三个1可以有两种不同的拿的策略

第一种是一次性拿三个1得到{3,3}

第二种是拿两个1得到{3,2,1}

这些正好是3+3, 3+2+1, 3+1+1+1

而从集合里面拿1这样的操作,利用堆栈就可以很容易的实现,我拿几个就弹出几个,然后把结果

压回栈中.但是这样的话并不是很直观,实际上使用两个栈来操作的话效果会更好.现在假设有两

个栈S1和S2.将S1栈全部压入1,S2栈为空.S1栈元素的个数就是我们输入要分解的整数,就像题

目输入的是6,那么S1栈里面就是6个1. 现在我们要做的事情就是从S1栈里面弹出N个1然后相加

把结果压入S2栈中,一直到S1栈空的时候,就将S2栈中的元素作为结果输出.

 

从前面的分析,我们可以把递归分成两个方面的,一个方面是深度的递归,就是不同层次之间的转变

的递归,另外一方面的递归是广度的递归,把同一层中的大数再分小,直至不能再分.举例子来说就是

6 -> 5+1 -> 4+2 -> 3+3这里是深度递归

3+3 -> 3+2+1 -> 3+1+1+1 这里是广度递归

 

运用到我们从S1栈弹出的元素来说,那么第一次弹几个元素就代表着深度,而第二次弹出的元素个

数只能是<=第一次弹出的元素的个数.第三次弹出的又要<=第二次弹出的 一直到S1栈空为止.

 

举例子来说

假设我们输入的是6,即我们要把6拿来分解.S1就应该有6个1 S2开始的时候是空.

1.第一次弹6个1,把6压入S2,这个时候S1空 ->输出6

2.第一次弹5个1,把5压入S2,这时候S1还剩下一个1,S2有一个5. 下一次弹出栈时候我只能弹出

一个1,压入S2,现在S1空 S2内为{1,5} 输出5+1

3.第一次弹4个1,S2{4},这里因为S1剩下的元素个数>1所以会出现不同的弹出的策略(广度递归

分解)

①第二次弹出两个1,S1空 S2{2,4} 输出 4 + 2

②第二次弹出一个1,第三次弹出一个1, S1空 S2{1,1,4}输出4+1+1

4.第一次弹出三个1, S1{1,1,1} S2{3} 因为S1剩下的元素个数大于1产生不同的弹出策略

①第二次弹出三个1,S1空 S2{3,3} 输出3+3

②第二次弹出两个1,S1{1} S2{2,3} ,继续弹出一个1 S1空 S2{1,2,3} 输出 3+2+1

③第二次弹出一个1,S1{1,1} S2{1,3},弹出一个1 S1{1} S2{1,1,3}, 弹出一个1 S1空

S2{1,1,1,3}

......如此一直到

第一次弹出一个1 S1{1,1,1,1,1,1} S2{1},弹出一个1 S1{1,1,1,1} S2{1,1} 弹出一个

S1{1,1,1} S2{1,1,1} ......最后S1空 S2{1,1,1,1,1,1} 输出1+1+1+1+1+1

#include<stdio.h>
#include<stdlib.h>
 
void output(int *a,int top2)      //输出结果
{  
    int i;
    for(i=0;i<top2-1;i++)
    {
        printf("%d+",a[i]);
    }
    printf("%d\n",a[i]);
}

void partion(int top1,int top2,int *a)
{
    if(top1==0)              //如果s1中已无元素,则划分完毕,输出
    {
        output(a,top2);
    }
    else
    {
        for(int i=top1;i>=1;i--)    
        {
            if(top2==0||i<=a[top2-1])      
            {
                a[top2]=i;                  //从s1中取出的1的个数压入s2
                partion(top1-i,top2+1,a);   //对s1中剩下的1再次进行取栈操作
            }
        }
    }
}

int main(void)
{
    int top1,top2;
    int *a;
    while(scanf("%d",&top1)==1&&top1>=0)
    {
        top2=0;
        a=(int *)malloc(top1*sizeof(int));
        partion(top1,top2,a);
    }
    return 0;
}

转载于:https://www.cnblogs.com/dolphin0520/archive/2011/07/10/2102150.html

<think>好的,我现在需要解决如何根据前序遍历和后序遍历来构造二叉树的问题。这个问题看起来有点挑战性,特别是因为前序和后序遍历的组合不像前序和中序那样直接确定结构。让我仔细想想。 首先,回顾一下二叉树遍历的基本知识。前序遍历的顺序是根节点、左子树、右子树,而后序遍历则是左子树、右子树、根节点。已知前序和中序可以唯一确定二叉树的结构,因为中序遍历能明确划分左右子树。但是前序和后序的组合可能存在多种结构,比如当树只有一个子节点时,无法确定是左还是右。不过题目中提到“无重复值”,这可能帮助解决歧义? 根据引用中的问题,比如引用[2]和[3],题目要求根据前序和后序构造二叉树。可能的思路是利用前序的第一个节点是根,后序的最后一个节点也是根。然后找到左子树的根,并在后序中找到对应的位置,从而分割左右子树。 比如,假设前序是根左右,后序是左右根。那么前序的第二个元素可能是左子树的根,然后在后序中找到这个元素的位置,该位置之前的元素属于左子树,之后到根之前的是右子树。这样就能将前序和后序数组分割为左右子树的部分,递归构建。 例如,前序数组为pre = [1,2,4,5,3,6,7],后序数组post = [4,5,2,6,7,3,1]。根是1,前序第二个元素是2,即左子树的根。在post中找到2的位置,假设在索引2,那么post中左子树部分是4,5,2,而剩下的部分是6,7,3。对应的前序左子树部分是2,4,5,右子树是3,6,7。这样递归处理左右部分。 但需要考虑当左子树或右子树不存在的情况。例如,如果前序的第二个元素和后序的倒数第二个元素相同,那么可能根只有一个子树,这时候可能需要处理为左或右。但题目中说“无重复值”,所以可能这种情况可以明确处理? 另外,关键是如何确定左子树的长度。假设在前序中找到左子树的根(即pre[1]),然后在post中找到该值的索引,该索引左边的元素都属于左子树,这样就能确定左子树的大小,从而分割前序和后序数组。 具体步骤可能如下: 1. 根节点是pre[0],创建根节点。 2. 如果pre的长度为1,则返回根。 3. 否则,左子树的根是pre[1]。 4. 在post数组中找到pre[1]的索引位置,记为left_len。左子树的节点数目是left_len + 1。 5. 分割前序数组:左子树的前序是pre[1 : left_len + 1],右子树的前序是pre[left_len + 1 : ]。 6. 分割后序数组:左子树的后序是post[0 : left_len + 1],右子树的后序是post[left_len + 1 : -1](因为最后一个是根节点)。 7. 递归构建左子树和右子树。 需要注意的是,当左子树不存在时,即pre[1]在post中可能对应右子树的根,这时候可能需要调整分割方式。但根据题目中的条件,可能这种情况不会出现?或者需要特别处理。 例如,当原树的结构导致左子树为空时,前序的第二个元素就是右子树的根。这时候,在post中找到该元素的位置,应该分割左子树长度为0,剩下的作为右子树。但这样处理是否正确? 例如,考虑前序为[1,3,6,7],后序为[6,7,3,1]。根是1,左子树的根应该是3?但在这种情况下,左子树不存在,3其实是右子树的根。这时候,按照之前的步骤,分割左子树的长度为在post中找到3的位置,即索引2,那么左子树的长度是2+1=3?这样会导致前序分割后的左子树部分为3,6,7,但实际这些都是右子树的节点。这时候显然会出现错误。 这说明这种方法在存在单子树的情况下可能无法正确分割。因此,可能需要另一种方法。或者题目是否保证树是满的,或者每个节点都有0或2个子节点?这可能影响解法。 根据题目描述,引用[2]和[3]中的问题允许构造可能的二叉树,可能答案并不唯一,但题目可能需要返回任意一种可能的结构。例如,当无法确定左右子树时,可以选择将子树作为左或右。但题目中的解法可能需要明确的方法。 可能正确的做法是,假设左子树的根存在,并分割前序和后序数组,如果分割后的左子树部分长度合理,则继递归。否则,可能需要处理为右子树。或者,当左子树长度为0时,将剩余部分作为右子树。 例如,在示例中,当pre = [1,2,3], post = [2,3,1]。根是1。左子树的根是2。在post中找到2的位置是0。左子树的长度是0+1=1。所以左子树的前序是pre[1:2],即[2],左子树的后序是post[0:1],即[2]。然后右子树的前序是pre[2:],即[3],后序是post[1:-1]即[3]。这样构建的树根左是2,右是3。 而当原树的结构是根只有右子树时,例如前序是[1,3,2],后序是[2,3,1]。按照同样的步骤,pre[1]是3,在post中找到3的位置是1。左子树长度是1+1=2,但pre的长度是3。分割左子树前序为pre[1:3],即[3,2],而右子树前序是空数组。这显然不合理,这说明这种情况下方法失效,因为原树的结构是根只有右子树,但按照当前方法会分割出左子树长度为2,导致错误。 这说明该方法在存在单子树的情况下可能无法正确工作。因此,可能需要调整思路。或者题目中的条件是否允许这种结构? 根据引用[2]的描述,题目中的preorder是“具有无重复值的二叉树的前序遍历”,这可能意味着树的结构可能允许单子树的情况,但此时前序和后序无法唯一确定结构,因此可能需要构造可能的任意一种结构。 比如,在单子树的情况下,比如根只有左子树或右子树,前序和后序的结构可能相同。例如,根为1,左子树为2,前序是[1,2],后序是[2,1]。或者根为1,右子树为2,前序是[1,2],后序是[2,1]。这两种情况的前序和后序是相同的,无法区分。因此,在这种情况下,题目可能允许返回任意一种结构,例如默认作为左子树。 因此,在构造时,当左子树的可能分割存在时,就按照左子树分割;如果无法分割,则视为右子树? 所以,可能的算法步骤是: 1. 创建当前根节点为pre[start_pre]。 2. 如果只剩下一个节点,返回根。 3. 否则,找到左子树的根pre[start_pre +1]。 4. 在post数组中找到该左子树根的位置,记为pos。 5. 左子树的大小为pos - start_post +1。 6. 分割左子树和右子树的pre和post数组。 7. 递归构造左子树和右子树。 但需要处理start和end的索引,这可能需要更细致的参数传递。 例如,在递归函数中,参数包括前序的起始和结束位置,后序的起始和结束位置。假设前序数组是pre,后序数组是post。 当前根是pre[pre_start]。如果pre_start == pre_end,返回该节点。否则,左子树的根是pre[pre_start +1]。在post数组中找到该值的索引,记为left_root_post_index。左子树的节点数目是left_root_post_index - post_start +1。因为后序数组中,左子树的范围是从post_start到left_root_post_index,而该数目即为左子树的节点数目。 然后,左子树在前序中的范围是pre_start+1到pre_start + left_count。右子树在前序中的范围是pre_start + left_count +1到 pre_end. 对应的后序数组中,左子树的后序范围是post_start到left_root_post_index,右子树的后序范围是left_root_post_index +1到 post_end -1(因为最后一个元素是当前根)。 这样,递归构造左子树和右子树。 例如,pre数组为根左右,post数组为左右根。左子树的根在pre中是pre[pre_start+1],在post中找到它的位置,得到左子树的长度。然后分割。 这样,当左子树存在时,可以正确分割。如果左子树不存在,比如pre[pre_start+1]实际上是右子树的根,那么在post中找到的位置可能在右子树的范围里,导致分割后的左子树数目超过前序数组中的长度,这可能需要处理。或者这种情况下,当左子树数目为0,则可能将整个剩余部分作为右子树? 或者,题目中的测试用例保证可以唯一确定子树结构?这可能要看题目是否允许。 例如,引用[3]中的问题描述:给定两个整数数组preorder和postorder,其中preorder是前序遍历,postorder是后序遍历,构造二叉树。可能存在多个答案,返回任意一个即可。因此,在这种情况下,只要构造出一个可能的二叉树即可,无需唯一确定。 因此,在算法中,当存在左子树的根时,按照分割左子树的方式处理,不管是否有右子树。即使原树实际上应该只有右子树,这样的分割可能将部分右子树节点误认为左子树,但因为允许返回任意可能的答案,所以这可能是可行的。 例如,当原树的根只有右子树,但前序的第二个元素是右子树的根,按照算法分割左子树时,假设该元素在post中的位置是k,那么左子树的数目是k - post_start +1。这可能导致左子树的数目超过pre中剩余的长度,或者可能分割出正确的结构? 例如,前序是[1,3,2], post是[2,3,1]. 根是1。左子树的根是3。在post中找到3的位置是1。左子树的数目是1 -0 +1=2。那么在前序中,左子树的部分是pre[1..2],即[3,2]。而后序的左子树部分是post[0..1],即[2,3]. 这显然是不对的,因为前序中的左子树应该是根左,但这里分割出来的部分对应的是整个右子树的结构。这样构建出来的树根节点的左子树是3,其左右子树是2,但后序显示左子树的后序是2,3,这说明3是左子树的根,其后序是左、右、根,即3的左是2,但此时前序是3,2,说明3的子树是根右结构,即3的右是2。此时后序的左子树部分后序是2,3,符合这样的结构。所以,构建出来的树是根1的左子树是3,而3的右子节点是2。这确实符合前序和后序的遍历结果。 虽然原树的结构可能应为根1的右子树是3,3的左子树是2,但根据前序和后序,这两种结构的前序和后序结果是一样的。因此,算法构造的树是其中一种可能的情况,而题目允许返回任何一种,所以算法是可行的。 综上,算法的大致步骤如下: 递归函数 build(pre, pre_start, pre_end, post, post_start, post_end): 1. 如果pre_start > pre_end,返回null。 2. 创建根节点root,值为pre[pre_start]。 3. 如果pre_start == pre_end,返回root。 4. 否则,找到左子树的根的值left_val = pre[pre_start+1]。 5. 在post数组的post_start到post_end-1的范围内找到left_val的位置left_post_index。 6. 计算左子树的节点数目left_size = left_post_index - post_start +1。 7. 分割前序的左子树部分:pre_start+1到pre_start+left_size。 8. 分割后序的左子树部分:post_start到left_post_index。 9. 分割前序的右子树部分:pre_start+left_size+1到pre_end。 10. 分割后序的右子树部分:left_post_index+1到post_end-1。 11. 递归构建左子树和右子树。 需要注意的是,在递归时,要确保分割的索引不会越界,并且当左子树的大小为零时,如何处理?例如,当left_val在post中的位置是post_end-1,此时分割后的左子树数目可能超出范围? 或者,当pre的长度为n,每个递归步骤分割后的左右子树的总节点数应等于原节点数减一(根节点)。 例如,原前序数组长度为len,分割后的左子树长度是left_size,右子树长度是 len -1 - left_size。 这可能在索引处理时需要特别注意。 现在,我需要将这个逻辑转化为代码。以Python为例,可能递归函数需要传递前序和后序的数组,以及各自的起始和结束索引。或者,考虑到数组的切片操作可能更简单,每次递归传递前序和后序的子数组。 例如: def build(pre, post): if not pre: return None root = TreeNode(pre[0]) if len(pre) ==1: return root left_val = pre[1] # 在post中找到left_val的索引 left_post_index = post.index(left_val) left_size = left_post_index +1 # 因为post的当前范围是整个数组,所以左子树的节点数目是left_post_index +1? # 左子树的前序是 pre[1:1+left_size] # 右子树的前序是 pre[1+left_size:] # 左子树的后序是 post[:left_post_index+1] # 右子树的后序是 post[left_post_index+1:-1] root.left = build(pre[1:1+left_size], post[:left_post_index+1]) root.right = build(pre[1+left_size:], post[left_post_index+1:-1]) return root 测试这个代码是否可行。 以例子pre = [1,2,4,5,3,6,7], post = [4,5,2,6,7,3,1]。根是1,左子树的根是2。在post中2的索引是2。left_size =2+1=3?此时左子树的前序是pre[1:4],即[2,4,5]。左子树的后序是post[:3],即[4,5,2]. 构建左子树,递归调用: 左子树的根是2,左子树的根在pre中的下一个元素是4。在post中找到4的索引?但此时的post是左子树的后序数组,即[4,5,2]。所以,在左子树的后序中找到4的索引是0。left_size=0+1=1。所以左子树的前序是pre[1:2],即[4]。构建节点4,其左右子树为空。然后右子树的前序是pre[2:4],即[5]. 此时左_size是1,所以递归构建右子树:pre[2:4]中的元素是5,对应的后序数组是post[1:3-1]?或者原问题中的递归调用传递的是post[left_post_index+1:-1],即 post[left_post_index+1:-1] 是对于原来的整个post数组来说的? 这里可能存在问题。例如,当递归处理左子树的时候,传递的后序数组是post[:left_post_index+1],即左子树的后序是整个post数组的前left_post_index+1部分。然后在递归调用中,左子树的处理需要在这个子数组内进行操作。例如,在左子树的后序数组中找到其左子树的根的位置。因此,原来的代码中的索引处理可能不正确,因为在递归调用中传递的是子数组,所以left_post_index是相对于整个post数组的位置,而不是相对于当前子数组的位置。这将导致错误。 比如,在第一次调用中,post是完整的数组。当处理左子树时,传入的后序数组是post的前三个元素,即[4,5,2]。此时,在该子数组中,寻找左子树的根(即4的下一个元素?或者原pre中的pre[1+1]=4?是的。在左子树的前序数组pre[1:4]是[2,4,5],所以pre[1]在这里是2,pre[2]是4,所以在处理左子树时,build的参数是pre的左子树部分:即[2,4,5]和post的左子树部分 [4,5,2]。这时候,在递归调用中,处理根节点2的左子树。此时,pre中的第一个元素是2,下一个元素是4,所以在左子树的前序数组中,pre[1]是4。需要在当前的post子数组(即[4,5,2])中找到4的索引,即0。所以 left_size =0 +1=1。左子树的前序是pre[1:2],即[4],对应的后序数组是post[:1](即[4])。这样,构建根节点4。此时,递归调用正确。 这说明,原代码中的问题可能出现在索引的处理上。当递归调用时,传递给build函数的post数组已经是当前子树的后序遍历结果,因此在寻找left_val的位置时,应该在该子数组中寻找。例如,在第一次调用中,原post是整个数组,在找到left_val的位置后,分割后的左子树后序数组是post[:left_post_index+1]。当处理左子树的递归调用时,传入的后序数组是该子数组,此时在这个子数组内寻找新的left_val的位置。 但原代码中的post.index(left_val)是在整个post数组中寻找,这显然错误。例如,在递归处理左子树时,post参数已经变为子数组,而left_val的查找应该在该子数组中进行。 因此,原代码存在错误。这说明在传递数组的切片时,每次递归调用中的post参数是当前子树的后序数组,此时需要在该数组中找到left_val的索引,而不是在原数组中。 例如,在递归处理左子树时,传递的post数组是原数组的一部分。比如,在第一次调用时,post是完整的数组,寻找left_val的位置在完整数组中的索引。但之后,处理左子树时,post数组变为子数组,这时寻找left_val的位置应该在该子数组中的索引,而不是原数组中的索引。所以原代码中的post.index(left_val)会返回全局索引,而不是相对于当前子数组的索引,这会导致错误。 这说明,原代码在递归处理时,传入的后序数组是子数组,但index的查找是针对原数组的,这是错误的。正确的做法是在当前递归调用的post数组(即子数组)中找到left_val的位置。 例如,在Python中,当传递post[:left_post_index+1]作为参数,那么在递归调用中的post是该子数组。此时,在递归调用的函数中,要找到left_val的位置应该在这个子数组中的索引,而不是原数组中的索引。 因此,原代码的问题出在这里。正确的做法是,在递归调用时,传递子数组,并且在子数组中查找left_val的位置。 所以,修改代码,确保每次递归调用中的post参数是当前子树的后序数组,然后在其中查找left_val的索引。 例如,修改后的代码: def build(pre, post): if not pre: return None root = TreeNode(pre[0]) if len(pre) ==1: return root left_val = pre[1] # 在当前post数组中找到left_val的索引 left_post_index = post.index(left_val) left_size = left_post_index +1 # 左子树节点数目为left_post_index +1(因为post数组是当前子树的后序,左子树的后序是前left_post_index +1个元素) # 左子树的前序是 pre[1:1+left_size] # 右子树的前序是 pre[1+left_size:] # 左子树的后序是 post[:left_post_index+1] # 右子树的后序是 post[left_post_index+1:-1] (因为当前post的最后一个元素是当前根,需要去掉) root.left = build(pre[1:1+left_size], post[:left_post_index+1]) root.right = build(pre[1+left_size:], post[left_post_index+1:-1]) return root 现在,假设pre是[1,2,3], post是[2,3,1]。第一次递归调用,left_val是2,在post中找到索引0。left_size=0+1=1。左子树的前序是pre[1:2],即[2],后序是post[:1],即[2].递归调用构建左子树。此时左子树的pre是[2], post是[2],返回节点2。右子树的前序是pre[2:]=[3],后序是post[1:-1]=post[1:2],即[3]. 构建右子树,返回节点3。这样,根1的左是2,右是3。符合预期。 另一个测试用例:pre=[1,3,2], post=[2,3,1]. 第一次递归调用,left_val是3,在post中的索引是1。left_size=1+1=2。左子树的前序是pre[1:3],即[3,2],后序是post[:2]=[2,3]. 构建左子树,此时pre是[3,2], post是[2,3]. 进入递归调用,根是3。pre的长度是2>1。left_val是pre[1]=2。在当前的post数组[2,3]中找2的索引,是0。left_size=0+1=1。左子树的前序是pre[1:2],即[2],后序是post[:1]=[2]. 递归调用返回节点2作为左子树的根。右子树的前序是pre[2:2](空),后序是post[1:-1]=post[1:1](空)。所以,根3的左子树是2,右子树为空。最终,整个树结构是根1的左子树是3,3的左子树是2。而原问题中的pre和post符合这个结构。 所以,该算法在这种情况下可以构造出符合前序和后序遍历的树结构。虽然原树可能可以有另一种结构(如根1的右子树是3,3的右子树是2),但根据前序和后序的输入,算法构造的树是有效的。 因此,这个算法是正确的,并且可以处理单子树的情况,只要题目允许返回任意可能的答案。 因此,最终的代码逻辑是正确的。</think>要基于前序遍历(preorder)和后序遍历(postorder)构建二叉树,需利用两者的特性:前序的根节点在首位,后序的根节点在末位。以下是具体步骤: 1. **确定根节点**:前序的首元素 `pre[0]` 是根节点,后序的末元素 `post[-1]` 也是根节点,两者一致。 2. **分割子树**:前序的第二个元素 `pre[1]` 是左子树的根节点,在后序中找到该值的索引 `pos`,左子树的节点数为 `pos + 1`。前序和后序中左子树的范围分别为 `pre[1 : pos + 2]` 和 `post[0 : pos + 1]`,剩余部分为右子树。 3. **递归构建**:对左子树和右子树重复上述过程。 ### 示例代码 ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def constructFromPrePost(preorder, postorder): if not preorder: return None root = TreeNode(preorder[0]) if len(preorder) == 1: return root left_val = preorder[1] left_post_index = postorder.index(left_val) left_size = left_post_index + 1 root.left = constructFromPrePost(preorder[1:1+left_size], postorder[:left_post_index+1]) root.right = constructFromPrePost(preorder[1+left_size:], postorder[left_post_index+1:-1]) return root ``` ### 示例分析 假设 `preorder = [1,2,4,5,3,6,7]` 和 `postorder = [4,5,2,6,7,3,1]`: 1. 根节点为 `1`。 2. 左子树的根为 `2`,在后序中找到 `2` 的索引为 `2`,左子树节点数为 `3`。 3. 左子树的前序为 `[2,4,5]`,后序为 `[4,5,2]`;右子树的前序为 `[3,6,7]`,后序为 `[6,7,3]`。 4. 递归构建左右子树,最终得到完整二叉树[^3]。 ### 注意事项 - 当树的节点只有一个子节点时,前序和后序无法唯一确定该子节点是左或右,此时算法会默认构造一种可能的结构[^2]。 - 时间复杂度为 $O(n^2)$(因每次递归需线性查找索引),可通过哈希表优化至 $O(n)$。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值