First, let's write a recursive function that returns the index of the first negative number.
int first_negative(const double numbers[], int size, int current)
{
if (current >= size)
{
return -1;
}
if (numbers[current] < 0.0)
{
return current;
}
return first_negative(numbers, size, ++current);
}
This is nice and simple. Easy to read and understand. It doesn't fit the criteria, so it may not be obvious how this helps. But using this, let's write the more complicated function.
int first_negative_if_has_positives(const double numbers[], int size)
{
if (size <= 0)
{
return -1;
}
if (numbers[0] < 0.0)
{
return (first_nonnegative(numbers, size, 1) >= 0) ? 0 : -1;
}
return first_negative(numbers, size, 1);
}
The basic logic here is simple. If the first number in the array is negative, check if there are any positive numbers in the array. If there are, return 0 (the index of the first element in the array, which we already know is negative). If not, return -1 because all the numbers are negative. Otherwise if the first number is not negative, we know that there are some positives, so we can just look for the first negative number.
Now we need first_nonnegative
, which is essentially the same function as first_negative
with a different test.
int first_nonnegative(const double numbers[], int size, int current)
{
if (current >= size)
{
return -1;
}
if (numbers[current] >= 0.0)
{
return current;
}
return first_nonnegative(numbers, size, ++current);
}
Now we have a complete solution. While this is more code than the other solutions, it will actually do fewer operations. The other solutions don't make full use of the elegance of recursion. They try to carry state from call to call that is unnecessary. They have to check that state in each call. Instead of carrying that state around, this solution uses the state of the first number to determine what it needs to learn. Then it uses one of two functions depending on that initial state.
Let's look back at the criteria:
return -1
if the numbers are all negative or all positive. This does that.
- Find the index of the first negative number otherwise. This does that.
- Using recursion. While the initial function is not recursive itself, it does use two recursive functions to generate the answer. It uses no loops.
- Only built-in C++ features. I'm not entirely sure what this means, but this solution only uses function calls,
if
statements, and return
. It seems to fit.
Complexity is the enemy of good software. It decreases performance and increases bugs. If you find yourself adding complexity, it is often helpful to step back and ask if you're going the wrong direction.
none_negative == true
as assignment, when it is not... \$\endgroup\$