I have an array of numbers, A = [2,6,4,7,8,3,2,4,6,3]. I am trying to write an algorithm which recursively finds the max number in the array, however you once you select a number you need to skip the next two numbers. So for example if you pick the first number 2, you cant select 6 or 4, but you can select any number after that. So for example the solution for this array would be to pick the numbers 6,8,6 to make 20.
You can solve this problem either iteratively or recursively. The iterative solution would be more efficient.
A recursive solution in Java might look like following (not checking for empty arrays):
private int maxSumGap(int[] array, int gap, int start) {
// Basis case is the start position is at the last position of the array
if (start == array.length - 1;) {
// Maximum is the only value
return array[start];
// Case if there are values after the gap
} else if (start < array.length - 1 - gap) {
// Compare the recursive calls with start position + 1 with the sum of start
// position + 1 + gap plus the value at the start position
return Math.max(
maxSumGap(array, gap, start + 1),
maxSumGap(array, gap, start + gap + 1) + array[start]
);
// Case if there are no values after the gap
} else {
// Compare the recursive calls with start position + 1 with the value at the
// start position
return Math.max(
maxSumGap(array, gap, start + 1),
array[start]
);
}
}
Related
Please help me understand how the following code always returns the smallest value in the array. I tried moving position of 3 but it always manages to return it irrespective of the position of it in the array.
let myA = [12,3,8,5]
let myN = 4
function F4(A,N)
{
if(N==1){
return A[0]
}
if(F4(A,N-1) < A[N-1]){
return F4(A,N-1)
}
return A[N-1]
}
console.log(F4(myA,myN))
This is quite tricky to get an intuition for. It's also quite important that you learn the process for tackling this type of problem rather than simply be told the answer.
If we take a first view of the code with a few comments and named variables it looks like this:
let myA = [12,3,8,5];
let myN = myA.length;
function F4(A, N) {
// if (once) there is only one element in the array "A", then it must be the minimum, do not recurse
if (N === 1){
return A[0]
}
const valueFromArrayLessLastEl = F4(A,N-1); // Goes 'into' array
const valueOfLastElement = A[N-1];
console.log(valueFromArrayLessLastEl, valueOfLastElement);
// note that the recursion happens before min(a, b) is evaluated so array is evaluated from the start
if (valueFromArrayLessLastEl < valueOfLastElement) {
return valueFromArrayLessLastEl;
}
return valueOfLastElement;
}
console.log(F4(myA, myN))
and produces
12 3 // recursed all the way down
3 8 // stepping back up with result from most inner/lowest recursion
3 5
3
but in order to gain insight it is vital that you approach the problem by considering the simplest cases and expand from there. What happens if we write the code for the cases of N = 1 and N = 2:
// trivially take N=1
function F1(A) {
return A[0];
}
// take N=2
function F2(A) {
const f1Val = F1(A); // N-1 = 1
const lastVal = A[1];
// return the minimum of the first element and the 2nd or last element
if (f1Val < lastVal) {
return f1Val;
}
return lastVal;
}
Please note that the array is not being modified, I speak as though it is because the value of N is decremented on each recursion.
With myA = [12, 3, 8, 5] F1 will always return 12. F2 will compare this value 12 with 3, the nth-1 element's value, and return the minimum.
If you can build on this to work out what F3 would do then you can extrapolate from there.
Play around with this, reordering the values in myA, but crucially look at the output as you increase N from 1 to 4.
As a side note: by moving the recursive call F4(A,N-1) to a local constant I've prevented it being called twice with the same values.
An interesting problem is to assign labels (0, 1 or 2) for every node in a tree (not necessarily binary), where no parent-child pair can have the same label. In addition, we need to maximize the sum of all labels, i.e., use as little 0 as possible. Return the minimum number of 0 labels used. Some leaf nodes have been pre-labeled. We cannot change those labels. If there are no way to assign labels, for example, one parent node has children pre-labeled with all three labels, return negative infinity.
I am trying dynamic programming on this. One possible recurrence is that OPT(v) returns the number of 0 used to label v’s subtree, and we start at the overall root. When recurse down the tree, try to label each v’s children 0, 1 and 2 (by manipulating v.label field in each node) and see which option returns the minimum number of 0. If we reach bottom and a leaf node has been pre-labeled, we can’t explore all labels but to use the given label. If the leaf node is not pre-labeled, try each label, same as above. The tree itself can be used as my memorization structure where the label is stored in each node’s .label field. But I am not sure how to write the recurrence explicitly, especially for the recursive case when I explore all possible labels for every child of current node. I have no idea to express this combination and get the minimum of it. The base case is fairly simple, perhaps return 1 if the leaf is labeled 0 and return 0 otherwise.
Your idea looks fine. Just one thing to improve: the memoization should concern not just one label value, but possibly all 3 label values (0, 1 and 2). For each label you would (per node) memoize what the minimum number of zeroes is in that node's tree (where it is the root) when that label is assigned to it.
Then, depending on which choice you made for the parent node, you would look at the two possible labels that remain and choose the label which has the least number of zeroes linked to it.
For the below implementation I have used this tree as example:
*
/ \
* * ___
/|\ / \ \
1 * * 2 * *
/ \ \
* 2 2
/|\
2 * 0
The asterisks are nodes that have no label.
So the algorithm would start at the root and temporarily assign it a 0, then see what effect and possibilities that leaves for the children. Then for each child go through the possible values it can have (not zero), ...and recurse deeper into the tree, each time backtracking -- registering the count of 0 labels -- and continuing with the next possible label for the node (and going down the tree again unless memoization is available).
For the above example we can see that an optimal labeling would be:
0
/ \
2 1 ___
/|\ / \ \
1 1 1 2 0 0
/ \ \
1 2 2
/|\
2 2 0
The root and its left child could swap values -- it doesn't matter. The result is 4 zeroes.
Here is the implementation:
// Main algorithm:
function triple(node, parentLabel=-1) {
let choices = node.label !== undefined ? [node.label] : [0,1,2];
let minCount = Infinity;
for (let label of choices) {
if (label === parentLabel) continue; // We cannot use same label as parent has
let count = node.memo[label]; // Already memoized?
if (count === undefined) { // No...
count = 0;
for (let child of node.children) {
count += triple(child, label); // recur
if (count >= minCount) break; // not better...
}
node.memo[label] = count;
}
if (label === 0) count++; // Count the zero
if (count < minCount) minCount = count; // better!
}
// Minimum number of 0-labels if parent has the given parentLabel
return minCount;
}
class Node {
constructor(label, ...children) {
this.label = label;
this.children = children;
this.memo = [undefined, undefined, undefined];
}
}
// Short-cut function for creating a Node instance with or without label
function N(...children) {
let label = undefined;
if (typeof children[0] === "number") { // first argument is a label
label = children.shift(); // extract first argument
}
return new Node(label, ...children);
}
// Demo
let tree = N(
N(
N(1), N(), N()
),
N(
N(2),
N(
N(
N(2), N(), N(0)
),
N(2)
),
N(
N(2)
)
)
)
console.log("input tree:");
console.log(tree);
let count = triple(tree);
console.log("Number of zeroes:", count);
This implementation would return Infinity when there is no valid labelling possible.
I'm trying to improve my recursion skill(reading a written recursion function) by looking at examples. However, I can easily get the logic of recursions without local variables. In below example, I can't understand how the total variables work. How should I think a recursive function to read and write by using local variables? I'm thinking it like stack go-hit-back. By the way, I wrote the example without variables. I tried to write just countThrees(n / 10); instead of total = total + countThrees(n / 10); but it doesn't work.
with total variable:
int countThrees(int n) {
if (n == 0) { return 0; }
int lastDigit = n % 10;
int total = 0;
total = total + countThrees(n / 10);
if (lastDigit == 3) {
total = total + 1;
}
return total;
}
simplified version
int countThrees(int x)
{
if (x / 10 == 0) return 0;
if (x % 10 == 3)
return 1 + countThrees(x / 10);
return countThrees(x / 10);
}
In both case, you have to use a stack indeed, but when there are local variables, you need more space in the stack as you need to put every local variables inside. In all cases, the line number from where you jump in a new is also store.
So, in your second algorithme, if x = 13, the stack will store "line 4" in the first step, and "line 4; line 3" in the second one, in the third step you don't add anything to the stack because there is not new recursion call. At the end of this step, you read the stack (it's a First in, Last out stack) to know where you have to go and you remove "line 3" from the stack, and so.
In your first algorithme, the only difference is that you have to add the locale variable in the stack. So, at the end of the second step, it looks like "Total = 0, line 4; Total = 0, line 4".
I hope to be clear enough.
The first condition should read:
if (x == 0) return 0;
Otherwise the single 3 would yield 0.
And in functional style the entire code reduces to:
return x == 0 ? 0
: countThrees(x / 10) + (x % 10 == 3 ? 1 : 0);
On the local variables:
int countThrees(int n) {
if (n == 0) {
return 0;
}
// Let an alter ego do the other digits:
int total = countThrees(n / 10);
// Do this digit:
int lastDigit = n % 10;
if (lastDigit == 3) {
++total;
}
return total;
}
The original code was a bit undecided, when or what to do, like adding to total after having it initialized with 0.
By declaring the variable at the first usage, things become more clear.
For instance the absolute laziness: first letting the recursive instances calculate the total of the other digits, and only then doing the last digit oneself.
Using a variable lastDigit with only one usage is not wrong; it explains what is happening: you inspect the last digit.
Preincrement operator ++x; is x += 1; is x = x + 1;.
One could have done it (recursive call and own work) the other way around, so it probably says something about the writer's psychological preferences
The stack usage: yes total before the recursive call is an extra variable on the stack. Irrelevant for numbers. Also a smart compiler could see that total is a result.
On the usage of variables: they can be stateful, and hence are useful for turning recursion into iteration. For that tail recursion is easiest: the recursion happening last.
int countThrees(int n) {
int total = 0;
while (n != 0) {
int digit = n % 10;
if (digit == 3) {
++total;
}
n /= 10; // Divide by 10
}
return total;
}
How do I efficiently calculate the index of the first "true" value in an OpenCL vector:
float4 f = (float4)(1, 2, 3, 4);
int i = firstTrue(f > 2);
In the example I would like to get i=2 because 3 is the first value greater than 2.
I have looked at all functions in http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/ but have found nothing.
Is this such an uncommon operation?
How do I calculate this (on my own) without much branching/code duplication?
I'm not aware of a built-in function that does exactly what you want, but I have some ideas on how you could do it. There might be a simpler solution, but I've only had one cup of coffee so far. The idea is to leverage the "count leading zeros" function "clz". You just need to convert the results of your conditional into bit positions in an integer.
Create a boolean vector with true/false state set by the comparison
Do a dot product of that against an integer vector with pre-defined values that correspond to bit positions.
The first bit set will correspond to the index you're asking for. Use clz() or a bithack to find that bit index.
In code, something like this (untested and might need adjusting):
float4 f = (float4)(1, 2, 3, 4);
int4 greater = (f > 2);
int4 bits = (int4)(8, 4, 2, 1);
int sum = dot(greater, bits); // maybe this needs to use float
int index = clz(sum); // might need offset applied
You'll need to offset or invert the result from clz to get 0,1,2,3 but that's just addition or subtraction.
Working Code
int firstTrue(int4 v) {
return 4 - (clz(0) - clz((v.x & 8) | (v.y & 4) | (v.z & 2) | (v.w & 1));
}
I'm extracting the min from a vector.
Say vector = [0, inf, inf, inf];
ExtractSmallest(vector) = 0;
and then vector = [0, 1, inf, inf];
but now, we've already seen 0. Thus,
ExtractSmallest(vector) = 1;
I represent this in my code by doing nodes.erase(nodes.begin() + smallestPosition);
But, I now realize that erasing is very bad. Is there a way to achieve this without erasing the vectors? Just skipping over the ones we've already seen?
Node* CGraph::ExtractSmallest(vector<Node*>& nodes)
{
int size = nodes.size();
if (size == 0) return NULL;
int smallestPosition = 0;
Node* smallest = nodes.at(0);
for (int i=1; i<size; ++i)
{
Node* current = nodes.at(i);
if (current->distanceFromStart <
smallest->distanceFromStart)
{
smallest = current;
smallestPosition = i;
}
}
nodes.erase(nodes.begin() + smallestPosition);
return smallest;
}
Option 1 You can have an additional vector<bool> on which you iterate in parallel. When you find the smallest element, mark that position in the bool vector as true. Whenever you iterate, skip the positions in both vectors that are marked as true.
Option 2 If order is not important, keep the number of elements removed so far. When you find the minimum, swap positions with the first non-excluded element. On a new iteration, start from the first non-excluded element.
Option 3 If order is not important, sort the array. (this takes O(n*log(n))). Removal will now take O(1) - you just exclude the first non-excluded element.
Option 4 If there are no duplicates, you can keep a std::set on the side with all excluded elements to this point. When you iterate, check whether the current element was already excluded or not.