I can't wrap my head around what's missing in my function to populate a binary tree vs the manual input.
Printing the head value along with its left & right node value doesn't seem to help me as well since it looks correct to me. However, printing out all the values after auto populating it produces a strange result.
The values of this binary tree will be coming from an array:
std::vector<ValueType> values = {
3,
7,4,
2,4,6,
8,5,9,3
};
Here is the tree relation:
3
(7,4)
7 4
(2,4) (4,6)
2 4 6
(8,5) (5,9) (9,3)
As you can see, the parent node is located above and its children is below enclosed in parenthesis.
row1: the root node 3 have left:7, right:4
row2: parent 7 have left:2, right:4
row2: parent 4 have left:4, right:6
...
This may seem not be a binary tree as mentioned from the comments, but look at it as a tree having null left or right node or a node having a shared children from its sibling (same row).
Below is the function to automatically populate the binary tree:
// ValueType is defined as an alias of int
void populateTree(BinaryTree* node, int rowCount, int lastIndex, std::vector<ValueType> values) {
for (int i = 0; i < rowCount; ++i) {
iterCount++;
int currentRow = (i * (i + 1)) / 2;
int x = i + 1;
int nextRow = (x * (x + 1)) / 2;
bool toggle = false;
for (int j = nextRow; j < nextRow + x; ++j) {
auto value = values[currentRow++];
node->value = node->parent != nullptr ? value : node->value;
if (j >= values.size())
continue;
auto leftValue = values[j + 0];
auto rightValue = values[j + 1];
node->left = new BinaryTree(node, leftValue);
node->right = new BinaryTree(node, rightValue);
if (j != currentRow)
std::cout << ", ";
std::cout << node->value << "(" << node->left->value << "," << node->right->value << ")";
node = toggle ? node->right : node->left;
toggle = !toggle;
}
std::cout << std::endl;
}
}
I have used the triangular number formula to map the array into row and column.
Now, to confirm if the code is working, starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom should be 23.
I've done this by traversing bottom-up and add all the adjacent node combinations. Here's the output of the result:
3(7,4)
7(2,4), 4(4,6)
2(8,5), 4(5,9), 6(9,3)
iter count: 14
============
[4, 4, 7, 3]:18
[5, 4, 2, 4, 7, 3]:25
[3, 6, 4, 2, 4, 7, 3]:29
[3, 6, 4, 2, 4, 7, 3]:29
[5, 2, 4, 7, 3]:21
[4, 7, 3]:14
[4, 3]:7
pair total sum: 54
There supposed to be a combinations of [n1, n2, n3, ...nX]:23.
However, if I build the binary tree manually, there is a correct combination:
3(7,4)
7(2,4), 4(4,6)
2(8,5), 4(5,9), 6(9,3)
iter count: 14
============
[8, 2, 7, 3]:20
[5, 2, 7, 3]:17
[5, 4, 7, 3]:19
[9, 4, 7, 3]:23 <--- this is the correct combination.
[5, 4, 4, 3]:16
[9, 4, 4, 3]:20
[9, 6, 4, 3]:22
[3, 6, 4, 3]:16
pair total sum: 83
Link to full source code: https://gist.github.com/mr5z/8249a9101e5bfdce4850602c3ea7ebf3
This is part of my solution to project euler#18
I’m not exactly sure about why your implement a tree structure an your own, but if your goal is visualisation of a certain tree structure: I would suggest you to use the boost cpp graph library in combination with graphiz
See an example here, which shows the construction of a family tree, in a more "graph orientated" way. Every graph (like a tree) has nodes and edges.
If you want to train your programming skills, please go ahead: I found the following example for a b-tree quite useful in my past.
Couldn’t you use a “normal” insertIntoTree function instead of you populateTree function ? Or is this a matter of performance for you ?
What you do here is an example of an XY problem (see here: Meta StackExchange: What is the XY problem? or there: GreyCat's Wiki: XyProblem) – you're trying to put your data into a tree structure just because they are presented in a way resembling a tree-like pyramid, but you did not check if such structure will actually help you solve the problem.
And the answer is: NO, it will not; it doesn't even fit the actual problem structure.
Your problem structure is a pyramid-like triangle of integer numbers, each of which has two nearest descendants (except those in the bottom row) and two nearest ancestors (except those on side edges, which have just one ancestor, and the top item, which has no ancestors at all). And you have already mapped that structure into a linear array by your 'triangular formula':
given a row number r in a range of 0 .. N-1 and a position in the row p in a range of 0 .. r and an array with indices 0 .. N*(N+1)/2-1,
the item (r,p) is stored in the array at index r*(r+1)/2 + p,
and its 'children' are (r+1,p) and (r+1,p+1).
That's all, the mapping allows you to access data in a 'triangular' manner, you need no tree to handle it.
Related
Given an integer n and array a, I need to find for each i, 1≤ i ≤ n, how many elements on the left are less than or equal to ai
Example:
5
1 2 1 1 2
Output
0 1 1 2 4
I can do it in O(N2) but I want to ask if there is any way to do it faster, since N is very large (N ≤ 106)?
You can use a segment tree, you just need to use a modified version called a range tree.
Range trees allow rectangle queries, so you can make the dimensions be index and value, and ask "What has value more than x, and index between 1 and n?"
Queries can be accomplished in O(log n) assuming certain common optimizations.
Either way O(N^2) is completely fine with N < 10^6.
I like to consider a bigger array to explain, so let's consider following array,
2, 1, 3, 4, 7, 6, 5, 8, 9, 10, 12, 0, 11, 13, 8, 9, 12, 20, 30, 60
The naïve way is to compare an element with all elements at left of it. Naïve approach has complexity of O(n^2) which make it not useful for big array.
If you look this problem closely you will find a pattern in it, and the pattern is Rather than comparing with each left element of an element we can compare first and last value of a range!. Wait a minute what is the range here?
These numbers can be viewed as ranges and there ranges can be created from traversing left to right in array. Ranges are as follows,
[2], [1, 3, 4, 7], [6], [5, 8, 9, 10, 12], [0, 11, 13], [8, 9, 12, 20, 30, 60]
Let’s start traversing array from left to right and see how we can create these ranges and how these ranges shall reduce the effort to find all small or equal elements at left of an element.
Index 0 have no element at its left to compare thus why we start form index 1, at this point we don’t have any range. Now we compare value of index 1 and index 0. Value 1 is not less than or equals to 2, so this is very import comparison, due to this comparison we know the previous range should end here because now numbers are not in acceding order and at this point we get first range [2], which contains only single element and number of elements less than or equals to left of element at index 1 is zero.
As continue with traversing left to right at index 2 we compare it with previous element which is at index 1 now value 1 <= 3 it means a new range is not staring here and we are still in same range which started at index 1. So to find how many elements less than or equals, we have to calculate first how many elements in current range [1, 3), in this case only one element and we have only one know range [2] at this point and it has one element which is less than 3 so total number of less than or equals elements at the left of element at index 2 is = 1 + 1 = 2. This can be done in similar way for rest of elements and I would like to jump directly at index 6 which is number 5,
At index 6, we have all ready discovered three ranges [2], [1, 3, 4, 7], [6] but only two ranges [2] and [1, 3, 4, 7] shall be considered. How I know in advance that range [6] is not useful without comparing will be explained at the end of this explanation. To find number of less than or equals elements at left, we can see first range [2] have only one element and it is less than 5, second range have first element 1 which is less than 5 but last element is 7 and it is greater than 5, so we cannot consider all elements of range rather we have to find upper bound in this range to find how many elements we can consider and upper bound can be found by binary search because range is sorted , so this range contains three elements 1, 3, 4 which are less then or equals to 5. Total number of elements less than or equals to 5 from two ranges is 4 and index 6 is first element of current range and there is no element at left of it in current range so total count = 1 + 3 + 0 = 4.
Last point on this explanation is, we have to store ranges in tree structure with their first value as key and value of the node should be array of pair of first and last index of range. I will use here std::map. This tree structure is required so that we can find all the range having first element less than or equals to our current element in logarithmic time by finding upper bound. That is the reason, I knew in advance when I was comparing element at index 6 that all three ranges known that time are not considerable and only two of them are considerable .
Complexity of solution is,
O(n) to travels from left to right in array, plus
O(n (m + log m)) for finding upper bound in std::map for each element and comparing last value of m ranges, here m is number of ranges know at particular time, plus
O(log q) for finding upper bound in a range if rage last element is greater than number, here q is number of element in particular range (It may or may not requires)
#include <iostream>
#include <map>
#include <vector>
#include <iterator>
#include <algorithm>
unsigned lessThanOrEqualCountFromRage(int num, const std::vector<int>& numList,
const std::map<int,
std::vector<std::pair<int, int>>>& rangeMap){
using const_iter = std::map<int, std::vector<std::pair<int, int>>>::const_iterator;
unsigned count = 0;
const_iter upperBoundIt = rangeMap.upper_bound(num);
for(const_iter it = rangeMap.cbegin(); upperBoundIt != it; ++it){
for(const std::pair<int, int>& range : it->second){
if(numList[range.second] <= num){
count += (range.second - range.first) + 1;
}
else{
auto rangeIt = numList.cbegin() + range.first;
count += std::upper_bound(rangeIt, numList.cbegin() +
range.second, num) - rangeIt;
}
}
}
return count;
}
std::vector<unsigned> lessThanOrEqualCount(const std::vector<int>& numList){
std::vector<unsigned> leftCountList;
leftCountList.reserve(numList.size());
leftCountList.push_back(0);
std::map<int, std::vector<std::pair<int, int>>> rangeMap;
std::vector<int>::const_iterator rangeFirstIt = numList.cbegin();
for(std::vector<int>::const_iterator it = rangeFirstIt + 1, endIt = numList.cend();
endIt != it;){
std::vector<int>::const_iterator preIt = rangeFirstIt;
while(endIt != it && *preIt <= *it){
leftCountList.push_back((it - rangeFirstIt) +
lessThanOrEqualCountFromRage(*it,
numList, rangeMap));
++preIt;
++it;
}
if(endIt != it){
int rangeFirstIndex = rangeFirstIt - numList.cbegin();
int rangeLastIndex = preIt - numList.cbegin();
std::map<int, std::vector<std::pair<int, int>>>::iterator rangeEntryIt =
rangeMap.find(*rangeFirstIt);
if(rangeMap.end() != rangeEntryIt){
rangeEntryIt->second.emplace_back(rangeFirstIndex, rangeLastIndex);
}
else{
rangeMap.emplace(*rangeFirstIt, std::vector<std::pair<int, int>>{
{rangeFirstIndex,rangeLastIndex}});
}
leftCountList.push_back(lessThanOrEqualCountFromRage(*it, numList,
rangeMap));
rangeFirstIt = it;
++it;
}
}
return leftCountList;
}
int main(int , char *[]){
std::vector<int> numList{2, 1, 3, 4, 7, 6, 5, 8, 9, 10, 12,
0, 11, 13, 8, 9, 12, 20, 30, 60};
std::vector<unsigned> countList = lessThanOrEqualCount(numList);
std::copy(countList.cbegin(), countList.cend(),
std::ostream_iterator<unsigned>(std::cout, ", "));
std::cout<< '\n';
}
Output:
0, 0, 2, 3, 4, 4, 4, 7, 8, 9, 10, 0, 11, 13, 9, 11, 15, 17, 18, 19,
Yes, It can be done in better time complexity compared to O(N^2) i.e O(NlogN). We can use the Divide and Conquer Algorithm and Tree concept.
want to see the source code of above mentioned two algorithms???
Visit Here .
I think O(N^2) should be the worst case. In this situation, we will have to traverse the array at least two times.
I have tried in O(N^2):
import java.io.*;
import java.lang.*;
public class GFG {
public static void main (String[] args) {
int a[]={1,2,1,1,2};
int i=0;
int count=0;
int b[]=new int[a.length];
for(i=0;i<a.length;i++)
{
for(int c=0;c<i;c++)
{
if(a[i]>=a[c])
{
count++;
}
}
b[i]=count;
count=0;
}
for(int j=0;j<b.length;j++)
System.out.print(b[j]+" ");
}`
The problem:
I have 2 arrays A[v] and M[w], with length v and w, respectively. Given two numbers p and q, I want to find how many combinations of the sum of two elements of these arrays satisfy the following condition:
p >= A[v] + M[w] <= q
An example:
Let:
A = [9, 14, 5, 8, 12, 2, 16],
v = 7,
M = [6, 2, 9, 3, 10],
w = 5,
p = 21,
q = 24
The answer will be 5, because of the following combinations:
14 + 9 = 23
14 + 10 = 24
12 + 9 = 21
12 + 10 = 22
16 + 6 = 22
What I have tried:
The following is an implementation of the problem in C++:
int K = 0; // K is the answer
for (int i=0; i<v; i++) {
for (int j=0; j<w; j++) {
if (A[v]+M[w] >= p && A[v]+M[w] <= q) {
++K;
}
}
}
As we can see the above code uses a loop inside a loop, thus making the time complexity of the program Ο(v×w), pretty slow for large arrays.
The question
Is there a fastest way to solve this problem?
Problem Summary: Given two arrays A and B with sizes v and w respectively, find the number of possible pairings of an element from A and an element from B such that the two elements have a sum that is >= p and <= q.
The simple, brute force algorithm is essentially what you have currently. The brute force algorithm would simply involve testing all possible pairs, which, as you said, would have a time complexity of O(v*w) because there are v ways to choose the first element and w ways to choose the second element when testing all the pairs.
As #thestruggler pointed out in their comment, sorting and binary search could be applied to create a significantly more efficient algorithm.
Let's say we sort B in ascending order. For the test case you provide, we would then have:
A = [9, 14, 5, 8, 12, 2, 16]
B = [2, 3, 6, 9, 10]
p = 21 and q = 24
Now, notice that for every element in a, we can calculate the range of elements in B that, when added to the element, would have a sum between p and q. We can actually find this range in O(logW) time by using what is called Binary Search. Specifically, if we were looking to pair the first number in A with numbers in B, we would binary search for the index of the first element that is >= 12 and then binary search for the index of the last element that is <= 15. The number of elements in B that would work in a pairing with the element from A is then just equal to 1 plus the difference between the two indexes.
Overall, this algorithm would have a complexity of O(WlogW + VlogW) (or O(VlogV + WlogV); if you want to go above and beyond your program could decide to sort the larger array to save time on testing). This is because sorting an array with N elements takes O(NlogN) time, and because each binary search over a sorted array with N elements takes O(logN).
This can also be solved in following way,
First sort both arrays,
[9, 14, 5, 8, 12, 2, 16] => [2, 5, 8, 9, 12, 14, 16]
[6, 2, 9, 3, 10] => [2, 3, 6, 9, 10]
Now iterate all elements of smaller array and do following,
[2, 3, 6, 9, 10],
current element is 2, subtract it with p, lets say it is num it means,
num = p - 2 = 21 - 2 = 19
Then all numbers in other array, grater than of equals to 19 will make sum 21 with 2. But no element in other array is grater than or equals to 19 It means by adding 2 with any element of other array can not grater than or equals to p,
Next element which is 3 and it also can not fulfill the requirement, same can be done with other element, so let's directly move to element 9 for explanation,
[2, 3, 6, 9, 10]
num = p - 9 = 21 - 9 = 12 and by getting lower bound of 12, we will get all numbers, those sum with 9 will be grater than or equal to p(21), as highlighted below,
[2, 5, 8, 9, 12, 14, 16],
Sum of these numbers with 9 is grater than or equals to p, now it is time to find how may of them will produce sum which is less then or equals to q, so to doing that we have to do following,
num = q - 9 = 24 - 9 = 15 and by finding upper bound of 15 will give all the numbers sum with 9 shall be less than of equals to q as highlighted below,
[2, 5, 8, 9, 12, 14, 16],
This way you can find all combinations having sum, p >= sum <= q,
#include <iostream>
#include <vector>
#include <algorithm>
std::size_t combinationCount(int p, int q, std::vector<int> arr1, std::vector<int> arr2){
std::sort(arr1.begin(), arr1.end());
std::sort(arr2.begin(), arr2.end());
std::vector<int>::const_iterator it1 = arr1.cbegin();
std::vector<int>::const_iterator endIt1 = arr1.cend();
std::vector<int>::const_iterator it2 = arr2.cbegin();
std::vector<int>::const_iterator endIt2 = arr2.cend();
if(arr2.size() < arr1.size()){
std::swap(it1, it2);
std::swap(endIt1, endIt2);
}
std::size_t count = 0;
for(; endIt1 != it1; ++it1){
int num = p - *it1;
std::vector<int>::const_iterator lowBoundOfPIt = std::lower_bound(it2, endIt2, num);
if(endIt2 != lowBoundOfPIt){
num = q - *it1;
std::vector<int>::const_iterator upBoundOfQIt = std::upper_bound(it2, endIt2, num);
count += (upBoundOfQIt - lowBoundOfPIt);
}
}
return count;
}
int main(){
std::cout<< "count = "<< combinationCount(21, 24, {9, 14, 5, 8, 12, 2, 16}, {6, 2, 9, 3, 10})<< '\n';
}
Output : 5
So, my goal is to capture data in a buffer.
I need speed and I just need a fixed size so I was thinking that a circular array would be the best.
But what I want to do is at each step to:
first, overwrite the latest information in the array with the newest that just arrived
next, using the all array starting from the oldest to the newest
repeat
I have difficulty to see how to handle the second step in C++ while being efficient. Or maybe something else than a circular array would be better? Any advise or point of view is welcome.
To have something more graphic:
for step in steps:
(current writing position = 2)
current buffer = [8, 9, 3, 4, 5, 6, 7]
new info = 10
overwrite buffer(new info)
new buffer = [8, 9, 10, 4, 5, 6, 7]
current writing position += 1 //(3)
array to use = [4, 5, 6, 7, 8, 9, 10]
function(array to use)
(I used integer following each other to see the chronology of each information in the buffer)
What I am thinking about is to copy the last part and first part and then concatenate them:
std::vector<int> buffer{8, 9, 10, 4, 5, 6, 7};
std::vector<int> oldest(&buffer[3],&buffer[6]);
std::vector<int> youngest(&buffer[0],&buffer[2]);
oldest.insert( oldest.end(), youngest.begin(), youngest.end() );
function(oldest)
If you know something that would be quicker please tell me.
If you really need speed you should not copy elements but use the index information you already have to access the elements in the right order.
So the handling function would just need a pointer to the array (or reference to std::vector), know the size and the current working pos.
// process from working pos to end of buffer
for(int i = current_pos; i < buffer_size; ++i) {
processElement(new_buffer [i]);
}
// process the remainder from begin to working pos
for(int i = 0; i < curent_pos; ++i) {
processElement(new_buffer [i]);
}
This should not be to hard to inplement as your working position marks both, the begin and end of your data to process.
This approach reduces the copy overhead n-fold where n is the number of extra array elements + 1 used.
Example: array with 2 extra elements
Note, in this case, the oldest value is on the left, the function has been called with pointer to arr[0] (start_pos = 0)
arr == [3, 4, 5, 6, 7, 8, 9, x, x]
now, lets insert the new value 10
arr == [3, 4, 5, 6, 7, 8, 9, 10, x]
start_pos += 1
call function with pointer to the second element (the old 3 won't be used)
function(arr + start_pos)
and now add the 11 and increment the working position (the old 4 won't be used)
arr == [3, 4, 5, 6, 7, 8, 9, 10, 11]
start_pos += 1
function(arr + start_pos)
Now, the array is full.
And only now it is needed to copy the last elements to the begin of the array (after the start_pos to the end) and set working_pos back to 0
depending on the number of extra elements this needs to be done only every 10th, 100th or even 1000th iteration !
result of copying would be:
arr == [6, 7, 8, 9, 10, 11, 9, 10, 11]
*
start_pos = -1 // prepare for the +1 in regular iteration.
next added value (12) will overwrite the * value
arr == [6, 7, 8, 9, 10, 11, 12, 10, 11]
start_pos += 1 // is 0 now
function(arr + start_pos)
Of course, you need one variable to determine the pos to insert the new element behind the other val or you derive from start_pos + nElemsToProcess
If your function() does only take std containers it is probably not the right choice to met the need for speed.
Given an n-ary tree stored in a parent array, with the children stored in an array of pointers to arrays where the first value is the number of children:
(childArray[2][0] shows that node 2 has 2 children, childArray[2][1] shows that its first child is 5, etc.)
parentArray = {3, 0, 3, -1, 3, 2, 2};
childArray = {{1, 1}, {0}, {2, 5, 6}, {3, 0, 2, 4}, {0}, {0}, {0}};
produces a tree that looks like this:
3
/|\
0 2 4
| |\
1 5 6
Using a queue, how can I output the tree level by level like so:
Level 1: 3
Level 2: 0, 2, 4
Level 3: 1, 5, 6
Levels 1 and 2 are easy, because level 1 is just the root and level 2 is just its children, but after that I can't figure out how to get it to get the children of the children.
One way of doing so would be using a queue data structure.
Start with some queue q, and place in the index of the (unique) item whose parent is -1. Now, at each step, until q is empty,
Perform v <- pop(q) (popping the head)
Print out v
For each child w of v, do push(q, v) (pushing ot the tail)
For example, here are the first steps for your case:
Initially, q = [3] (3 is the index of the item whose parent is -1).
We pop q, print out 3, and push 0, 2, and 4, so q = [0, 2, 4].
Now we pop q, print out 0, and push 1, so q = [2, 4, 1].
Almost by definition, since q is popped from the front and added to the back, the nodes will be processed level by level.
The complexity is linear in the number of nodes.
You will have to perform a BFS (Breadth First Search) on the tree, while maintaining the number of nodes pushed into the next level. Outline:
q.push(root); nodesInCurrentLevel = 1; nodesInNextLevel = 0; currentLevelIndex = 1;
while q is not empty do:
u = q.pop()
print currentLevelIndex and u
decrement nodesInCurrentLevel
for every child v of u do:
increment nodesInNextLevel
q.push(v)
if nodesInCurrentLevel is 0 do:
nodesInCurrentLevel = nodesInNextLevel
nodesInNextLevel = 0
increment currentLevelIndex
Of course, this would print the output as Level 2:0 Level 2:2, etc. You can store current level nodes in a temporary list within the loop and print as appropriate.
Suppose I have some sorted lists of integers and I want to convert them to their respective regex digit ranges, like so:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] => [0-9]
[0, 1, 2, 3, 4, 6, 7, 8, 9] => [0-46-9]
[0, 1, 3, 4, 5, 8, 9] => [013-589]
[0, 2, 4, 6, 8] => [02468]
I am not trying to regex match anything here. I am trying to generate a regex range from a set of digits.
I am really just looking to see if there is already some de facto algorithm for doing something like this.
Edit: Based on #Jerry_Coffin's answer, a Java-based algorithm:
List<Integer> digits = Arrays.asList(0, 1, 3, 4, 5, 8, 9);
StringBuilder digitRange = new StringBuilder().append('[');
int consecutive = 0;
for (int i = 0; i < digits.size(); i++) {
if (i == digits.size() - 1 || digits.get(i) + 1 != digits.get(i + 1)) {
if (consecutive > 1) {
digitRange.append('-');
}
digitRange.append(digits.get(i));
consecutive = 0;
} else {
if (consecutive == 0) {
digitRange.append(digits.get(i));
}
consecutive++;
}
}
digitRange.append(']');
System.out.println(digitRange.toString());
Output: [013-589]
Feel free to find improvements or problems.
Presumably you're starting from sorted input (if not, you almost certainly want to start by sorting the input).
From there, start from the first (unprocessed) item, write it out. Walk through the numbers as long as they're consecutive. Assuming you get more than two consecutive, write out a dash then the last of the consecutive numbers. If you got two or fewer consecutive, just write them to output as-is.
Repeat until you reach the end of the input.
I can propose a different approach.
Iterate through the list identifying intervals. We keep two variables left and right (interval bounds) and each time we have two not consecutive values we write the interval to a StringBuilder.
int[] list = new[] { 0, 1, 3, 4, 5, 8, 9 };
int left = 0;
int right = 0;
for (int i = 0; i < list.Length; i++)
{
if (i == 0) // first case
{
left = right = list[i];
continue;
}
if (list[i] - list[i - 1] > 1) // not consecutive
{
builder.AppendFormat(Write(left, right));
left = list[i];
}
right = list[i];
}
builder.AppendFormat(Write(left, right));// last case
builder.Append("]");
The write method:
private static string Write(int left, int right)
{
return
left == right
? left.ToString()
: right - left == 1
? string.Format("{0}{1}", left, right)
: string.Format("{0}-{1}", left, right);
}