【问题标题】:Binary tree with alternating sign具有交替符号的二叉树
【发布时间】:2015-02-23 06:58:02
【问题描述】:

给定一个具有以下属性的二叉树,它的所有叶节点都处于正(+)号,然后符号交替到该路径的根。所以一个节点可以有多个符号,具体取决于路径。

现在我们需要找出每条路径的总和和树的总和。

for ex:
there are 5 paths in the given binary tree.

path 1: 10-2+3-4 = 7

path 2: 19-8+2-3+4 = 14

path 3: 12-11+17-3+4 = 19

path 4: 2-9+1-4 = -10

path 5: 21-9+1-4 = 9


overall sum 39

这里的问题是确定每个节点的符号,该符号由其底层路径中的叶节点控制。

我可以想到一个具有 O(n) 时间复杂度和 O(n) 空间的解决方案,我可以将每个路径保存在从根到底部遍历的向量中,然后从叶节点开始确定每个节点的符号,从而计算总和每条路径。

现在任何人都可以提出任何改进的方法,空间复杂度为 O(1)。 任何递归或迭代方法都将是首选。

我希望我已经清楚地解释了这个问题。不过,如果有任何疑问,我会很快补充更多细节。

编辑:二叉树是这样存储和实现的,而不是在数组中

struct node
{
    int data;
    struct node* left;
    struct node* right;
};

struct node* newNode(int data)

{
  struct node* node = (struct node*)
                       malloc(sizeof(struct node));
  node->data = data;
  node->left = NULL;
  node->right = NULL;

  return(node);
}

int main()
{
  struct node *root = newNode(1);
  root->left        = newNode(2);
  root->right       = newNode(3);
  root->left->left  = newNode(4);
  root->left->right = newNode(5); 
}

在任何情况下都无法节省存储树所需的空间。请不要去制作树。假设给你一棵树的根节点,树已经建好了。

我说的是运行特定算法来回答问题所需的额外空间。

【问题讨论】:

  • 你需要最大化总和吗?无法理解判断非叶节点标志的标准。
  • 不,我们不需要最大化总和。标准很简单:叶节点处于正号,然后符号交替到该路径的根。所以一个节点可以有多个符号,具体取决于路径
  • O(1) 是什么意思,你必须至少通过节点一次
  • 您能解释一下您打算如何在 O(n) 时间和空间内完成它吗?
  • @sasha:我说的是 O(1) 空间而不是 O(1) 时间 O(1) 空间意味着不使用任何额外空间。我会通过使用路径数组 path[] 将当前根存储到叶路径来做到这一点。以自上而下的方式从根遍历到所有叶子。遍历时,将当前路径中所有节点的数据存储在数组path[]中。当我们到达一个叶子节点时,我们可以停下来。

标签: c++ algorithm tree


【解决方案1】:

好的,所以,如果我们可以从下到上遍历树,我们可以很容易地获得 O(1) 额外空间和 O(n^2) 时间复杂度的解:

for(every leaf in tree){

   Node node = leaf;
   int total = 0;
   int sign = 1;
   while(node != null){
       total += sign*node.value;
       node = node.parent;
       sign *= -1; 
   }
   print total;
}

对于时间复杂度为O(n)的自上而下的遍历,要获得O(1)的额外空间,需要更复杂的算法

Node node = root;
Node last = null;
int total = 0;
int sign = 1;
boolean back = false;
while(node != null){
     total += sign*node.value;
     if(node is leaf){
        if(sign == 1)
           print total;//Need to check if sign is not positive
        else
           print -total;
        back = true;//If this is leaf, we need to go back
        total -= sign*node.value;
        last = node;
        node = node.parent;
     }else if(back){
        if(last is left child){
           back = false;
           node = node.rightChild;
        }else{//We need to continue to go back if we are going back and this is right child 
           last = node;
           total -= sign*node.value;
           node = node.parent;
        } 
     }else{
        total += sign*node.value;
        node = node.leftChild;
     }
     sign *= -1; 

}

注意

  • 使用堆栈的从上到下的递归遍历或迭代遍历很容易产生 O(n) 的空间复杂度,所以要小心!

  • 没有每个Node中的父链接,我们无法解决这个问题,因为在这种情况下,需要一个类似堆栈的数据结构来遍历树。

更新:

由于我们可以改变树中节点的值,所以我们可以修改节点的左链接,将其用作到父节点的链接。

Node node = root;
Node last = null;
int total = 0;
int sign = 1;
boolean back = false;
while(node != null){
     total += sign*node.value;
     if(node is leaf){
        if(sign == 1)
           print total;//Need to check if sign is not positive
        else
           print -total;
        back = true;//If this is leaf, we need to go back
        total -= sign*node.value;
        Node tmp = last;//For leaf node, we can just use variable last
        last = node;
        node = tmp;
     }else if(back){
        if(last is not right child){
           back = false;
           last = node;
           node = node.rightChild;
        }else{//We need to continue to go back if we are going back and this is right child 
           last = node;
           total -= sign*node.value;
           node = node.leftChild;
        } 
     }else{
        total += sign*node.value;
        Node tmp = node.leftChild;
        node.leftChild = last;
        last = node;
        node = tmp;
     }
     sign *= -1; 

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-14
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多