对于二叉树,我想得到落在单个垂直线上的所有节点的总和。我想要每个Verticle节点中的节点总和
A
/ \
B C
/ \ / \
D E F G
/ \
H I
如果你看看上面的发球台
line 0 A E F so sum = A+E+F
line -1 B I so sum = B +I
line 1 C so sum = C
line 2 G so sum = G
我实现了以下算法
Map<Integer,Integere> mp = new HashMap<Integer,Integer>()
calculate(root,0);
void calculate(Node node, int pos){
if(node==null)
return ;
if(mp.containsKey(pos) ){
int val = mp.get(pos) + node.data;
mp.put(pos,val);
}
else{
mp.put(pos,node.data);
}
calculate(node.left,pos-1);
calculate(node.right,pos+1);
}
答案 0 :(得分:2)
您可以在深度优先顺序中访问二叉树,并使用偏移量来跟踪您相对于起始节点向左/右移动的距离。每次向左移动时,都会减小偏移量,每次向右移动都会增加偏移量。如果调用的访问过程的偏移量为0
,则表示被访问的节点与起始节点的偏移量相同(即它位于同一列中),因此必须添加其值。 / p>
伪代码:
procedure visit (node n, int offset) {
sumleft = 0
sumright = 0
if (n.left != null)
sumleft = visit(n.left, offset - 1)
if (n.right != null)
sumright = visit(n.right, offset + 1)
if (offset == 0)
return n.value + sumleft + sumright
else
return sumleft + sumright;
}
例如,如果你打电话
visit(A, 0)
您将收到以下电话:
visit(A, 0) -> E.value + F.value + A.value
visit(B, -1) -> E.value
visit(D, -2) -> 0
visit(H, -3) -> 0
visit(I, +2) -> 0
visit(E, 0) -> E.value
visit(C, +1) -> F.value
visit(F, 0) -> F.value
visit(G, +1) -> 0
另一个例子,从节点B
开始:
visit(B, 0)
visit(D, -1)
visit(H, -2)
visit(I, 0) -> here we return I.value
visit(E, +1)
当递归返回到初始调用visit(B, 0)
时,我们有sumleft = I.value
和sumright = 0
,因此我们会按预期返回最终结果B.value + I.value
。
O(n)的复杂性,因为一旦树的所有节点都以起始节点为根,您就会访问它。
在考虑上述算法之后,我意识到它有一个限制,当我们考虑如下的更复杂的树时,这种限制变得明显:
在这种情况下,visit(B, 0)
仍会返回B.value + I.value
,但这不是预期的结果,因为N
也在同一列上。以下算法应该解决这个问题:
procedure visit(node n, int c, int t) {
sumleft = 0;
sumright = 0;
if (n.left != null)
sumleft = visit(n.left, c - 1, t)
if (n.right != null)
sumright = visit(n.right, c + 1, t)
if (c == t)
return n.value + sumleft + sumright;
else
return sumleft + sumright;
}
这个想法基本相同,但我们现在有一个参数c
,它给出了当前列,参数t
是目标列。如果我们想要B
列中元素的总和,那么我们可以调用visit(A, 0, -1)
,也就是说我们总是从节点A
(根树)开始我们的访问,它位于第0列,我们的目标是第-1列。我们得到以下信息:
因此visit(A, 0, -1) = B + I + N
符合预期。
复杂度始终为O(n),其中n是树中节点的数量,因为我们使用深度优先后序访问整个树,并且我们只处理每个节点一次。
如果我们想要计算每列的总和,我们可以使用以下算法
procedure visit(node n, int c) {
if (n.left != null)
S{c} += n.value;
visit(n.left, c - 1)
visit(n.right, c + 1)
}
并调用visit(A, 0)
,其中A
是根节点。请注意,算法中的S{...}
是一个映射,其键是列数(..., - 2,-1,0,1,2,...)及其值(在算法结束时) )是该列中节点值的总和(S{1}
将是第1列中节点的总和)。如果我们注意索引(数组没有负索引),我们也可以使用数组而不是映射。算法仍然是O(n),因为我们只遍历整个树一次。但是,在这种情况下,我们需要额外的空间来存储所有列(地图或数组)的总和。如果我没弄错,高度为h
的二叉树将会有2*h + 1
列。
答案 1 :(得分:2)
C ++代码
int vertsum(Node* n, int cur_level, int target_level)
{
if (!n)
return 0;
int sum = 0;
if (cur_level == target_level)
sum = n->value;
return sum +
vertsum(n->left, cur_level-1, target_level) +
vertsum(n->right, cur_level+1, target_level);
}
调用示例:
vertsum(root, 0, 1);
修改强>
在澄清要求之后,这里是建议的代码。请注意,这是C ++'ish,并不完全使用Java或C ++的标准API列表,但你应该明白这一点。我假设addNodeBefore
和addNodeAfter
初始化节点的数据(即ListNode::counter
)
void vertsum(TreeNode* n, int level, ListNode& counter)
{
if (!n)
return;
counter.value += n->value;
counter.index = level;
if (! counter.prev)
addNodeBefore(counter);
vertsum(n->left, level-1, counter.prev);
if (! counter.next)
addNodeAfter(counter);
vertsum(n->right, level+1, counter.next);
return;
}
答案 2 :(得分:0)
以下怎么样? (在节点类中,假设getData返回整数值,hasRight()和hasLeft()是布尔值,指示是否存在右/左分支,getRight()和getLeft()返回右/左分支中的下一个节点。
public int calculateVerticalLine(int numLine) {
return calculateVerticalLineRecursive(numLine, 0);
}
protected int calculateVerticalLineRecursive(int numLine, int curPosition) {
int result = 0;
if(numLine == curPosition) result += this.getData();
if(hasRight()) result += getRight().calculateVerticalLineRecursive(numLine, curPosition+1);
if(hasLeft()) result += getLeft().calculateVerticalLineRecursive(numLine, curPosition-1);
return result;
}
答案 3 :(得分:0)
public class Solution {
public static int getSum(BinaryTreeNode<Integer> root) {
//Your code goes here.
if(root==null){
return 0;
}
int leftnodesum=getSum(root.left);
int rightnodesum=getSum(root.right);
return root.data+leftnodesum+rightnodesum;
}
}