给定二叉树,找到同一垂直线上的节点的垂直和。通过不同的垂直线打印所有总和。
要了解相同的垂直线,我们需要先定义水平距离。如果两个节点具有相同的水平距离(HD),则它们位于同一垂直线上。 HD的想法很简单。根的HD为0,右边缘(连接到右子树的边缘)被认为是+1水平距离而左边缘被认为是-1水平距离。例如,在上面的树中,节点4的HD为-2,节点2的HD为-1,5和6的HD为0,节点7的HD为+2。
示例:
1
/ \
2 3
/ \ / \
4 5 6 7
树有5条垂直线
Vertical-Line-1只有一个节点4 =>垂直和是4
Vertical-Line-2:只有一个节点2 =>垂直和是2
Vertical-Line-3:有三个节点:1,5,6 =>垂直和是1 + 5 + 6 = 12
Vertical-Line-4:只有一个节点3 =>垂直和是3
Vertical-Line-5:只有一个节点7 =>垂直和是7
因此预期产出为4,2,12,3和7
我的解决方案: 我想出了这个问题的o(nlong(n))解决方案。这个想法是:
(1)使用preorder遍历获取每个节点的HD,并将HD及其相关节点存储在一个数组中。
(2)按HD排序数组
(3)遍历排序的数组以打印结果。
我确信这不是解决这个问题的最佳方法。任何人都可以帮我提供更好的解决方案吗?
答案 0 :(得分:11)
你不能在第一次遍历中全部完成吗?定义从HD到sum的字典(哈希映射)。
对于您访问的每个节点,将其值添加到正确的字典键 - 这是O(n)
解决方案。
d = {}
def traverse(node, hd):
if not node:
return
if not hd in d:
d[hd] = 0
d[hd] = d[hd] + node.value
traverse(node.left, hd - 1)
traverse(node.right, hd + 1)
然后只需致电traverse(root, 0)
答案 1 :(得分:0)
这是C中的一个。返回后的vsum数组将有结果。
void vsum(struct tree *t, int vsum[], int depth) {
if (t == NULL)
return;
vsum[depth] += t->val;
depth++;
vsum(t->left, vsum, depth);
vsum(t->right, vsum, depth);
}
答案 2 :(得分:0)
使用级别顺序遍历,使用具有元素的队列以及与其HD值相邻的队列。以下算法将给出O(n)[未经过运行测试]
的解决方案void findVertSum( struct node *root)
{
enqueue(root);
enqueue(0);
while(!isEmptyQueue())
{
tempnode = dequeue();
vertIndex = dequeue();
sum[vertIndex] += tempnode->val;
// Array cant be used because there will be sum[-1], sum[-2] etc, which will give error. This line hense only gives the idea to store solution.
if(t->left)
{
enqueue(t->left);
enqueue(vertIndex - 1);
}
if(t->right)
{
enqueue(t->right);
enqueue(vertIndex + 1);
}
}
答案 3 :(得分:0)
这是我在O(n)`
中运行的解决方案 #include <iostream>
#include <vector>
using namespace std;
vector<int> v;
int size;
typedef struct node
{
int data;
struct node *left, *right ;
} node, *ptr;
ptr newNode(int item)
{
ptr temp = new node;
temp->data = item;
temp->left = temp->right = NULL;
return temp;
}
void printVerticalSumUtil(ptr root, int line)
{
if (root == NULL) return;
else
{
v[line] += root->data;
printVerticalSumUtil(root->left, line - 1);
printVerticalSumUtil(root->right, line + 1);
}
}
void printVerticalSum(ptr root)
{
if (root == NULL)
return;
//Calculating the line No for the root
ptr curr = root;
int line = 0;
while (curr->left != NULL)
{
curr = curr->left;
line++;
}
size = 2 * line + 1; //Total No of Lines
line++; //Adjusting line no for root
for (int i = 1; i <= size; ++i) //Initializing lines to zero
v.push_back(0);
printVerticalSumUtil(root, line);
for (int i = 1; i <= size; ++i)
{
cout << "Sum of Line " << i << " is " << v[i] << endl;
}
}
int main()
{
ptr root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
printVerticalSum(root);
return 0;
}`
答案 4 :(得分:0)
#define HD_OFFSET 16
void vertical_sum(Node *node, int hd, int sum[], int *min, int *max){
/* We are offseting the index to access array correctly.
Root will be at HD_OFFSET/2 index and all vertical lines on left will
be at 0 to HD_OFFSET/2 and right side will be on HD_OFFSET/2 to HD_OFFSET */
int index = hd + HD_OFFSET/2;
if(!node) return;
/* to keep track of min and max index filled in sum array */
if(index > (*max)) (*max) = index;
if(index < (*min)) (*min) = index;
sum[index]+= node->value;
/*If we are moving on the left side,
we will pass index as one less the current */
vertical_sum(node->left, hd-1, sum, min, max);
/*If we are moving on the right side,
we will pass index as one more the current */
vertical_sum(node->right, hd+1, sum, min, max);
}
答案 5 :(得分:0)
对于迟到的解决方案感到抱歉。 有几种方法可以解决这个问题。 Itay Karo已经使用hashmap提供了一个很好的解决方案。您还可以使用双向链接列表:
printVerticalSum(TreeNode root)
{
if(root==null)
return -1;
allocate node doubleLinkList //initialize,
printVerticalSumUtil(root, doubleLinkList);
//write the function to print double linked list
System.out.println(doubleLinkList.toString())
}
printVerticalSumUtil(TreeNode root, ListNode listNode)
{
if(root==NULL) return;
if(root.left!=NULL)
if(listNode.prev!=NULL)
listNode.prev.data += root.data;
else
ListNode t = new ListNode(root.data);
t.next=listNode;
listNode.prev = t;
findVerticalSum(root.left, listNode.prev)
if(root.right!=NULL)
if(listNode.next!=NULL)
listNode.next.data += root.data;
else
ListNode t = new ListNode(root.data);
t.prev=listNode;
listNode.next = t;
findVerticalSum(root.right, listNode.next)
}
更多细节 - http://k2code.blogspot.in/2011/12/vertical-sum-of-binary-tree.html。
感谢。
答案 6 :(得分:0)
以下代码将完成这项工作:
使用的语言:Java
// Algorithm for calculating the vertical sum of a binary tree.
static void verticalSum(Node root, int[] sum, int index)
{
/*
The sum array contains the sum of each
vertical line starting from the leftmost vertical line.
*/
if(root==null)
{
return;
}
else
{
sum[index]+=(int)root.data;
verticalSum(root.left, sum, index-1);
verticalSum(root.right, sum, index+1);
}
}
您需要使用以下代码调用上述函数:
//Algorithm for calculating the vertical sum of a binary tree.
int level=countLevels(root);
int a=1,d=2,n=level;
int sizeOfArray= a+(n-1)*d;
int index=sizeOfArray/2;
int[] sum=new int[sizeOfArray];
verticalSum(root, sum, index);
System.out.print("Vertical Sum of the binary tree is : ");
for(int i=0;i<sizeOfArray;i++)
{
System.out.print(", " + sum[i]);
}
countLevels(root)函数在下面提供:
// Algorithm for calculating the number of levels
static int countLevels(Node root)
{
int count=0,c=1,i=0,level=0;
Queue<Node> queue=new LinkedList<Node>();
Node temp = null;
queue.add(root);
while(true)
{
if(queue.isEmpty())
{
break;
}
level++;
for(i=0;i<c;i++)
{
temp=queue.remove();
if(temp.left!=null)
{
queue.add(temp.left);
count++;
}
if(temp.right!=null)
{
queue.add(temp.right);
count++;
}
}
c=count;
count=0;
}
return level;
}
答案 7 :(得分:0)
//经过测试和运作的例子
package tree;
import java.util.TreeMap;
public class VerticalSumProblem
{
public static void main(String[] args)
{
VerticalSumProblem verticalSum = new VerticalSumProblem();
TreeNode treeNode = verticalSum.new TreeNode(1);
treeNode.left = verticalSum.new TreeNode(2);
treeNode.right = verticalSum.new TreeNode(3);
treeNode.left.left = verticalSum.new TreeNode(4);
treeNode.left.right = verticalSum.new TreeNode(5);
treeNode.right.left = verticalSum.new TreeNode(6);
treeNode.right.right = verticalSum.new TreeNode(7);
//treeNode.right.right.left =verticalSum.new TreeNode(8);
verticalSum.printTree(treeNode);
verticalSum.findVerticalSum(treeNode);
}
private void findVerticalSum(TreeNode root)
{
if(root == null) return;
TreeMap<Integer,Integer> _mappings = new TreeMap<Integer,Integer>();
findVerticalSum(root,_mappings,0);
if (_mappings != null)
{
System.out.println(_mappings.entrySet());
}
}
//if goes left -- and if goes right ++
private void findVerticalSum(TreeNode treeNode,TreeMap<Integer,Integer> mappings, int level)
{
if(treeNode == null) return;
TreeNode treeNodeLeft,treeNodeRight;
if(treeNode.left != null)
{
treeNodeLeft = treeNode.left;
findVerticalSum(treeNodeLeft, mappings,level - 1);
}
int sum = mappings.get(level) == null ? 0 : mappings.get(level);
mappings.put(level, treeNode.data + sum);
if( treeNode.right != null)
{
treeNodeRight = treeNode.right;
findVerticalSum(treeNodeRight,mappings, level + 1);
}
}
/* Create following Binary Tree
1
/ \
2 3
/ \ / \
4 5, 6 7
*/
private void printTree(TreeNode treeNode)
{
TreeNode treeNodeLeft,treeNodeRight;
if(treeNode == null) return;
if(treeNode.left != null || treeNode.right != null)
{
treeNodeLeft = treeNode.left;
treeNodeRight = treeNode.right;
System.out.println("rootValue ="+treeNode.data);
System.out.println("Left child of ="+treeNode.data +" is : "+ getNodedata(treeNodeLeft));
System.out.println("Right child of ="+treeNode.data+" is : "+ getNodedata(treeNodeRight)+"\n");
printTree(treeNodeLeft);
printTree(treeNodeRight);
}
}
private int getNodedata(TreeNode treeNode)
{
if(treeNode != null)
{
return treeNode.data;
}
return -1;
}
private class TreeNode
{
private int data;
private TreeNode left,right;
TreeNode(int data)
{
this.data = data;
left = null;
right = null;
}
}
}
//vertical sum
/// | | | | |
// | | 1 | |
/// | 2 | 3 |
// 4 | 5,6 | 7
// 0
// 1 -1
// 2 0,0 -2
//
答案 8 :(得分:0)
这是我在c ++中的简单解决方案: - 在这里,我使用地图来存储基于距离中心的水平距离的总和。
Node *vsumprint(Node *root,int level,map<int,int> &mp){
if(root==NULL)return NULL;
Node *temp = vsumprint(root->left,--level,mp);
if(temp==NULL){
level++;
}
if(mp.find(level)!=mp.end()){
mp[level] = root->data+mp[level];
}
else{
mp[level] = root->data+mp[level];
}
return vsumprint(root->right,++level,mp);
}
void printVertical(Node *root)
{
map<int,int> mp;
vsumprint(root,0,mp);
for(auto it:mp){
cout<<it.second<<" ";
}
}
答案 9 :(得分:0)
这是我在C#中的解决方案:请注意顺序很重要,它如何输出,所以我必须创建一个类并应用自定义排序。
public class Location
{
public int x, y, val;
public Location(int x, int y, int val)
{
this.x = x;
this.y = y;
this.val = val;
}
}
private List<Location> locations;
public IList<IList<int>> VerticalTraversal(TreeNode root)
{
// Each location is a node's x position, y position, and value
locations = new List<Location>();
dfs(root, 0, 0);
locations.Sort(Comparer<Location>.Create((a,b) =>
{
if (a.x != b.x)
return a.x.CompareTo(b.x);
return a.y != b.y ? a.y.CompareTo(b.y) : a.val.CompareTo(b.val);
}));
var result = new List<IList<int>>();
result.Add(new List<int>());
int prev = locations[0].x;
foreach(Location loc in locations)
{
// If the x value changed, it's part of a new report.
if (loc.x != prev)
{
prev = loc.x;
result.Add(new List<int>());
}
// We always add the node's value to the latest report.
result[result.Count - 1].Add(loc.val);
}
return result;
}
private void dfs(TreeNode node, int x, int y)
{
if (node != null)
{
locations.Add(new Location(x, y, node.val));
dfs(node.left, x - 1, y + 1);
dfs(node.right, x + 1, y + 1);
}
}