Create binary tree of fixed size - c

I am trying to create a binary tree. Only thing I am given is the number of the nodes in the tree. The first thing popped in to my head is to use an index(BFS order) to keep the track of the number of total nodes, then use a recursive definition. Here is my pseudocode to do that.
N = 10 //binary tree total node count
i = 0 //global integer
function()
if i > N
return True
create node i
i = i + 1
function(i) //left
i = i + 1
function(i) //right
I have to use a global variable in this definition which makes me feel like maybe I am violating recursion rules. Is there a better way to do what I do, if this is the way, can it be improved ?
Note: I am asking about the theoretical method, not the code.
Edit: I just realized this method fails. I am open for suggestions.
Clarification: The requirement for this tree is not to add an element to a depth, if the previous depth is not filled with nodes(all nodes have 2 children), pardon me for not mentioning this before, as for the stack I mentioned in the comments, it has nothing to do with the question, just the regular way of traversing trees iteratively.

A tree consists of three elements if defined recursively:
a root node
a left subtree, which is a tree itself
a right subtree, which is a tree itself
all of these may be NULL.
Now we can distribute the numbers in a range [a, b] into a tree in the following manner:
root contains (a + b) / 2
left subtree is built of range [a, (a + b) / 2 - 1] recursively
right subtree is built of the range [(a + b) / 2 + 1, b] recursively
A range with higher start than end may be considered as empty and results in a node being NULL. This distribution ensures that the left and right subtree differ at most by 1 in size and that each level is entirely filled up, before another level is getting filled.
E.g.:
N = 6
[0, 5]
[0, 1] 2 [3, 5]
[0] 1 [] [3] 4 [5]
[] 0 [] [] 3 [] [] 5 []
In addition this algorithm builds a BST (actually this basically the "reverse" of a binary search). Now for the algorithm itself:
function(a, b):
if b < a: return NULL
n = create node (a + b) / 2
n.left = function(a, (a + b) / 2 - 1)
n.right = function((a + b) / 2 + 1, b)
return n
The tree can be generated by calling:
function(1, N)
Alternatively any other parameters a and b should work, where a + N - 1 = b holds. The two parameters represent the range (both inclusive) which should be held by the tree.

Related

Find Minimum Score Possible

Problem statement:
We are given three arrays A1,A2,A3 of lengths n1,n2,n3. Each array contains some (or no) natural numbers (i.e > 0). These numbers denote the program execution times.
The task is to choose the first element from any array and then you can execute that program and remove it from that array.
For example:
if A1=[3,2] (n1=2),
A2=[7] (n2=1),
A3=[1] (n3=1)
then we can execute programs in various orders like [1,7,3,2] or [7,1,3,2] or [3,7,1,2] or [3,1,7,2] or [3,2,1,7] etc.
Now if we take S=[1,3,2,7] as the order of execution the waiting time of various programs would be
for S[0] waiting time = 0, since executed immediately,
for S[1] waiting time = 0+1 = 1, taking previous time into account, similarly,
for S[2] waiting time = 0+1+3 = 4
for S[3] waiting time = 0+1+3+2 = 6
Now the score of array is defined as sum of all wait times = 0 + 1 + 4 + 6 = 11, This is the minimum score we can get from any order of execution.
Our task is to find this minimum score.
How can we solve this problem? I tried with approach trying to pick minimum of three elements each time, but it is not correct because it gets stuck when two or three same elements are encountered.
One more example:
if A1=[23,10,18,43], A2=[7], A3=[13,42] minimum score would be 307.
The simplest way to solve this is with dynamic programming (which runs in cubic time).
For each array A: Suppose you take the first element from array A, i.e. A[0], as the next process. Your total cost is the wait-time contribution of A[0] (i.e., A[0] * (total_remaining_elements - 1)), plus the minimal wait time sum from A[1:] and the rest of the arrays.
Take the minimum cost over each possible first array A, and you'll get the minimum score.
Here's a Python implementation of that idea. It works with any number of arrays, not just three.
def dp_solve(arrays: List[List[int]]) -> int:
"""Given list of arrays representing dependent processing times,
return the smallest sum of wait_time_before_start for all job orders"""
arrays = [x for x in arrays if len(x) > 0] # Remove empty
#functools.lru_cache(100000)
def dp(remaining_elements: Tuple[int],
total_remaining: int) -> int:
"""Returns minimum wait time sum when suffixes of each array
have lengths in 'remaining_elements' """
if total_remaining == 0:
return 0
rem_elements_copy = list(remaining_elements)
best = 10 ** 20
for i, x in enumerate(remaining_elements):
if x == 0:
continue
cost_here = arrays[i][-x] * (total_remaining - 1)
if cost_here >= best:
continue
rem_elements_copy[i] -= 1
best = min(best,
dp(tuple(rem_elements_copy), total_remaining - 1)
+ cost_here)
rem_elements_copy[i] += 1
return best
return dp(tuple(map(len, arrays)), sum(map(len, arrays)))
Better solutions
The naive greedy strategy of 'smallest first element' doesn't work, because it can be worth it to do a longer job to get a much shorter job in the same list done, as the example of
A1 = [100, 1, 2, 3], A2 = [38], A3 = [34],
best solution = [100, 1, 2, 3, 34, 38]
by user3386109 in the comments demonstrates.
A more refined greedy strategy does work. Instead of the smallest first element, consider each possible prefix of the array. We want to pick the array with the smallest prefix, where prefixes are compared by average process time, and perform all the processes in that prefix in order.
A1 = [ 100, 1, 2, 3]
Prefix averages = [(100)/1, (100+1)/2, (100+1+2)/3, (100+1+2+3)/4]
= [ 100.0, 50.5, 34.333, 26.5]
A2=[38]
A3=[34]
Smallest prefix average in any array is 26.5, so pick
the prefix [100, 1, 2, 3] to complete first.
Then [34] is the next prefix, and [38] is the final prefix.
And here's a rough Python implementation of the greedy algorithm. This code computes subarray averages in a completely naive/brute-force way, so the algorithm is still quadratic (but an improvement over the dynamic programming method). Also, it computes 'maximum suffixes' instead of 'minimum prefixes' for ease of coding, but the two strategies are equivalent.
def greedy_solve(arrays: List[List[int]]) -> int:
"""Given list of arrays representing dependent processing times,
return the smallest sum of wait_time_before_start for all job orders"""
def max_suffix_avg(arr: List[int]):
"""Given arr, return value and length of max-average suffix"""
if len(arr) == 0:
return (-math.inf, 0)
best_len = 1
best = -math.inf
curr_sum = 0.0
for i, x in enumerate(reversed(arr), 1):
curr_sum += x
new_avg = curr_sum / i
if new_avg >= best:
best = new_avg
best_len = i
return (best, best_len)
arrays = [x for x in arrays if len(x) > 0] # Remove empty
total_time_sum = sum(sum(x) for x in arrays)
my_averages = [max_suffix_avg(arr) for arr in arrays]
total_cost = 0
while True:
largest_avg_idx = max(range(len(arrays)),
key=lambda y: my_averages[y][0])
_, n_to_remove = my_averages[largest_avg_idx]
if n_to_remove == 0:
break
for _ in range(n_to_remove):
total_time_sum -= arrays[largest_avg_idx].pop()
total_cost += total_time_sum
# Recompute the changed array's avg
my_averages[largest_avg_idx] = max_suffix_avg(arrays[largest_avg_idx])
return total_cost

Finding max sum with operation limit

As an input i'm given an array of integers (all positive).
Also as an input i`m given a number of "actions". The goal is to find max possible sum of array elements with given number of actions.
As an "action" i can either:
Add current element to sum
Move to the next element
We are starting at 0 position in array. Each element could be added only once.
Limitation are:
2 < array.Length < 20
0 < number of "actions" < 20
It seems to me that this limitations essentially not important. Its possible to find each combination of "actions", but in this case complexity would be like 2^"actions" and this is bad...))
Examples:
array = [1, 4, 2], 3 actions. Output should be 5. In this case we added zero element, moved to first element, added first element.
array = [7, 8, 9], 2 actions. Output should be 8. In this case we moved to the first element, then added first element.
Could anyone please explain me the algorithm to solve this problem? Or at least the direction in which i shoudl try to solve it.
Thanks in advance
Here is another DP solution using memoization. The idea is to represent the state by a pair of integers (current_index, actions_left) and map it to the maximum sum when starting from the current_index, assuming actions_left is the upper bound on actions we are allowed to take:
from functools import lru_cache
def best_sum(arr, num_actions):
'get best sum from arr given a budget of actions limited to num_actions'
#lru_cache(None)
def dp(idx, num_actions_):
'return best sum starting at idx (inclusive)'
'with number of actions = num_actions_ available'
# return zero if out of list elements or actions
if idx >= len(arr) or num_actions_ <= 0:
return 0
# otherwise, decide if we should include current element or not
return max(
# if we include element at idx
# we spend two actions: one to include the element and one to move
# to the next element
dp(idx + 1, num_actions_ - 2) + arr[idx],
# if we do not include element at idx
# we spend one action to move to the next element
dp(idx + 1, num_actions_ - 1)
)
return dp(0, num_actions)
I am using Python 3.7.12.
array = [1, 1, 1, 1, 100]
actions = 5
In example like above, you just have to keep moving right and finally pickup the 100. At the beginning of the array we never know what values we are going to see further. So, this can't be greedy.
You have two actions and you have to try out both because you don't know which to apply when.
Below is a python code. If not familiar treat as pseudocode or feel free to convert to language of your choice. We recursively try both actions until we run out of actions or we reach the end of the input array.
def getMaxSum(current_index, actions_left, current_sum):
nonlocal max_sum
if actions_left == 0 or current_index == len(array):
max_sum = max(max_sum, current_sum)
return
if actions_left == 1:
#Add current element to sum
getMaxSum(current_index, actions_left - 1, current_sum + array[current_index])
else:
#Add current element to sum and Move to the next element
getMaxSum(current_index + 1, actions_left - 2, current_sum + array[current_index])
#Move to the next element
getMaxSum(current_index + 1, actions_left - 1, current_sum)
array = [7, 8, 9]
actions = 2
max_sum = 0
getMaxSum(0, actions, 0)
print(max_sum)
You will realize that there can be overlapping sub-problems here and we can avoid those repetitive computations by memoizing/caching the results to the sub-problems. I leave that task to you as an exercise. Basically, this is Dynamic Programming problem.
Hope it helped. Post in comments if any doubts.

LeetCode Find All Numbers Disappeared in an Array Question

The problem I am doing is stated as follows:
Given an array nums of n integers where nums[i] is in the range [1, n], return an array of all the integers in the range [1, n] that do not appear in nums.
I found a solution that takes O(n) space fairly quickly however this problem has a condition to find a constant space solution and I do not understand the solution that is given. The constant space solution is recreated here as follows:
def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
# Iterate over each of the elements in the original array
for i in range(len(nums)):
# Treat the value as the new index
new_index = abs(nums[i]) - 1
# Check the magnitude of value at this new index
# If the magnitude is positive, make it negative
# thus indicating that the number nums[i] has
# appeared or has been visited.
if nums[new_index] > 0:
nums[new_index] *= -1
# Response array that would contain the missing numbers
result = []
# Iterate over the numbers from 1 to N and add all those
# that have positive magnitude in the array
for i in range(1, len(nums) + 1):
if nums[i - 1] > 0:
result.append(i)
return result
I don't understand how this code works. To me it seems that every element will be made negative in the first pass and therefore no values will be appended to the answer list. I ran it through a debugger and it seems that is not what is happening. I was hoping that someone can explain to me what it is doing.
Let's take an example:
nums = [4,3,2,7,8,2,3,1]
Now Let's iterate over it,
Index-1: Value = 4 -> Mark (Value - 1) -> (4-1) index element as negative provided that element is positive.
Now, nums = [4,3,2,-7,8,2,3,1]
In this do for every index,
You will come to this:
nums = [-4,-3,-2,-7,8,2,-3,-1]
The element at index = 4 and index = 5 are positive.
So, the answer is [4+1,5+1] = [5,6].
Hope you understood this🔑.

Count elements in 1st array less than or equal than elements in 2nd array python

I have an array Aof 21381120 elements ranking from [0,1]. I need to construct a new array B in which the element i contains the number of elements in A less than or equal than A[i].
My attempt:
A = np.random.random(10000) # for reproducibility
g = np.sort(A)
B = [np.sum(g<=element) for element in A]
I am still using a for loop, taking too much time. Since I have to do this several times I was wondering if exists a better way to do it.
EDIT
I gave an example of the array A for reproducibility. This does what is expected to. But I need it to be faster (for arrays having 2e9 elements).
For instance if:
A = [0.1,0.01,0.3,0.5,1]
I expect the output to be
B = [2, 1, 3, 4, 5]
You could use binary search to speed up searching in a sorted array. Binary search in numpy.
A = np.random.rand(10000) # for reproducibility
g = np.sort(A)
B = [np.searchsorted(g, element) for element in A]
Looks like sorting is the way to go because in a sorted array A, the number of elements less than or equal to A[i] is almost i + 1.
However, if an element is repeated, you'll have to look at the nearest element that's to the right of A[i]:
A = [1,2,3,4,4,4,5,6]
^^^^^ A[3] == A[4] == A[5]
Here, the number of elements <= A[3] is 3 + <number of repeated 4's>. Maybe you could roll your own sorting algorithm that would keep track of such repetitions. Or count the repetitions before sorting the array.
Then the final formula would be:
N(<= A[k]) = k + <number of elements equal to A[k]>
So the speed of your code would mainly depend on the speed of the sorting algorithm.

Finding blocks in arrays

I was looking over some interview questions, and I stumbled onto this one:
There's an m x n array. A block in the array is denoted by a 1 and a 0 indicates no block. You are supposed to find the number of objects in the array. A object is nothing but a set of blocks that are connected horizontally and/or vertically.
eg
0 1 0 0
0 1 0 0
0 1 1 0
0 0 0 0
0 1 1 0
Answer: There are 2 objects in this array. The L shape object and the object in the last row.
I'm having trouble coming up with an algorithm that would catch a 'u' (as below) shape. How should i approach this?
0 1 0 1
0 1 0 1
0 1 1 1
0 0 0 0
0 1 1 0
One approach would use Flood Fill. The algorithm would be something like this:
for row in block_array:
for block in row:
if BLOCK IS A ONE and BLOCK NOT VISITED:
FLOOD_FILL starting from BLOCK
You'd mark items visited during the flood fill process, and track shapes from there as well.
This works in C#
static void Main()
{
int[][] array = { new int[] { 0, 1, 0, 1 }, new int[] { 0, 1, 0, 1 }, new int[] { 0, 1, 1, 1 }, new int[] { 0, 0, 0, 0 }, new int[] { 0, 1, 1, 0 } };
Console.WriteLine(GetNumber(array));
Console.ReadKey();
}
static int GetNumber(int[][] array)
{
int objects = 0;
for (int i = 0; i < array.Length; i++)
for (int j = 0; j < array[i].Length; j++)
if (ClearObjects(array, i, j))
objects++;
return objects;
}
static bool ClearObjects(int[][] array, int x, int y)
{
if (x < 0 || y < 0 || x >= array.Length || y >= array[x].Length) return false;
if (array[x][y] == 1)
{
array[x][y] = 0;
ClearObjects(array, x - 1, y);
ClearObjects(array, x + 1, y);
ClearObjects(array, x, y - 1);
ClearObjects(array, x, y + 1);
return true;
}
return false;
}
I would use Disjoint sets (connected components).
At the begining, each (i,j) matrix element with value 1 is one element set itself.
Then you can iterate over each matrix element and for each element (i,j) you should join each adjacent position set {(i+1,j),(i-1,j),(i,j+1),(i,j-1)} to (i,j) set if its value is 1.
You can find an implementation of disjoint sets at Disjoint Sets in Python
At the end, the number of diffrent sets is the number of objects.
I would use a disjoint-set datastructure (otherwise known as union-find).
Briefly: for each connected component, build an "inverse tree" using a single link per element as a "parent" pointer. Following the parent pointers will eventually find the root of the tree, which is used for component identification (as it is the same for every member of the connected component). To merge neighboring components, make the root of one component the parent of the other (which will no longer be a root, as it now has a parent).
Two simple optimizations make this datastructure very efficient. One is, make all root queries "collapse" their paths to point directly to the root -- that way, the next query will only need one step. The other is, always use the "deeper" of the two trees as the new root; this requires a maintaining a "rank" score for each root.
In addition, in order to make evaluating neighbors more efficient, you might consider preprocessing your input on a row-by-row basis. That way, a contiguous segment of 1's on the same row can start life as a single connected component, and you can efficiently scan the segments of the previous row based on your neighbor criterion.
My two cents (slash) algorithm:
1. List only the 1's.
2. Group (collect connected ones).
In Haskell:
import Data.List (elemIndices, delete)
example1 =
[[0,1,0,0]
,[0,1,0,0]
,[0,1,1,0]
,[0,0,0,0]
,[0,1,1,0]]
example2 =
[[0,1,0,1]
,[0,1,0,1]
,[0,1,1,1]
,[0,0,0,0]
,[0,1,1,0]]
objects a ws = solve (mapIndexes a) [] where
mapIndexes s =
concatMap (\(y,xs)-> map (\x->(y,x)) xs) $ zip [0..] (map (elemIndices s) ws)
areConnected (y,x) (y',x') =
(y == y' && abs (x-x') == 1) || (x == x' && abs (y-y') == 1)
solve [] r = r
solve (x:xs) r =
let r' = solve' xs [x]
in solve (foldr delete xs r') (r':r)
solve' vs r =
let ys = filter (\y -> any (areConnected y) r) vs
in if null ys then r else solve' (foldr delete vs ys) (ys ++ r)
Output:
*Main> objects 1 example1
[[(4,2),(4,1)],[(2,2),(2,1),(1,1),(0,1)]]
(0.01 secs, 1085360 bytes)
*Main> objects 1 example2
[[(4,2),(4,1)],[(0,3),(1,3),(2,3),(2,2),(2,1),(1,1),(0,1)]]
(0.01 secs, 1613356 bytes)
Why not just look at all the adjacent cells of a given block? Start at some cell that has a 1 in it, keep track of the cells you have visited before, and keep looking through adjacent cells until you cannot find a 1 anymore. Then move onto cells that you have not looked yet and repeat the process.
Something like this should work:
while array has a 1 that's not marked:
Create a new object
Create a Queue
Add the 1 to the queue
While the queue is not empty:
get the 1 on top of the queue
Mark it
Add it to current object
look for its 4 neighbors
if any of them is a 1 and not marked yet, add it to queue

Resources