You are given a binary tree in which each node contains an integer value (which might be positive or negative). Design an algorithm to count the number of paths that sum to a given value. The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).
The question asks for count only but I went one step ahead and found the paths too.
The following is my attempt at this code. Please let me know how I can improve it. Also I think the time complexity of the code is \$O(n^2)\$ because of the following reasoning:
findPathsWithSumHelper
is called n times for each node in the tree.- This function goes through all the nodes below the
root
to find paths. - The total work done is \$n + 2 * \frac{n}{2} + 4 * \frac{n}{4} + \dots n * \frac{n}{n}\$ which equals \$O(n^2)\$.
- The work done in copying the arrays using
emplace_back
is \$O(n)\$ at each node in the tree and adds a constant to \$O(n^2)\$.
#include <iostream>
#include <vector>
using namespace std;
struct Tree{
struct Tree * left, *right;
int data;
Tree(int val): data(val), left(NULL), right(NULL){};
};
//insert nodes randomly in a BT
void insertNodeBT(Tree * &root, int val){
Tree * newNode = new Tree(val);
if(root==NULL){
root = newNode;
return;
}
int r = rand()%2;
if(r)
insertNodeBT(root->left, val);
else
insertNodeBT(root->right, val);
}
vector<vector<int>> findPathsWithSumHelper(Tree * root, int target, int prev, vector<int> path){
vector<vector<int>> res;
if(root == NULL){
return res;
}
path.push_back(root->data);
if(prev + root->data == target){
res.push_back(path);
}
vector<vector<int>> temp;
temp = findPathsWithSumHelper(root->left, target, prev+root->data, path);
for(auto i : temp){
res.emplace_back(move(i));
}
temp = findPathsWithSumHelper(root->right, target, prev+root->data, path);
for(auto i : temp){
res.emplace_back(move(i));
}
return res;
}
vector<vector<int>> findPathsWithSum(Tree * root, int target){
vector<vector<int>> res;
if(root == NULL){
return res;
}
vector<int> path;
res = findPathsWithSumHelper(root, target, 0, path);
vector<vector<int>> temp;
temp = findPathsWithSum(root->left, target);
for(auto i : temp){
res.emplace_back(move(i));
}
temp = findPathsWithSum(root->right, target);
for(auto i : temp){
res.emplace_back(move(i));
}
return res;
}
int main() {
Tree *root = NULL;
insertNodeBT(root, 4);
insertNodeBT(root, 6);
insertNodeBT(root, 2);
insertNodeBT(root, 7);
insertNodeBT(root, 5);
insertNodeBT(root, 1);
insertNodeBT(root, 3);
insertNodeBT(root, -1);
vector<vector<int>> res = findPathsWithSum(root, 6);
for (auto i : res){
for (auto j : i) {
cout << j << " ";
}
cout<<endl;
}
return 0;
}
Following is a better solution but it only returns the count and not the actual paths. I feel it is \$O(nlogn)\$ but not sure.
int findPathsWithSum(Tree * root, int target, unordered_map<int, int> m){
if(root==NULL)
return 0;
int res=0;
for(auto &it : m){
if(it.first+root->data == target)
res++;
m[it.first+root->data]++;
m.erase(it.first);
}
if(root->data == target)
res++;
m[root->data]++;
res += findPathsWithSum(root->left, target, m);
res += findPathsWithSum(root->right, target, m);
return res;
}
insertNodeBST()
function works, it always sorts the values. But for the question, will that always be the case? Is it possible to end up with a binary tree that has, say 5 with 278 to the left or -43 to right? \$\endgroup\$insertNodeBST()
twice. Is that intentional? I don't think that will compile. \$\endgroup\$