Skip to main content
added 346 characters in body
Source Link
Juho
  • 3.6k
  • 20
  • 18

The optimal algorithm will scan the input array once; indeed, you can show by a standard adversary argument that no faster algorithm exists.

Your current solution does two passes over the input array (the two invocations of np.where) which as stated seems wasteful. Given that we know there's a linear lower bound, the natural question is: how do weOne simple way to solve the problem in a single pass? The answer is to use np.argmax which will take linear time:

import numpy as np
arr = np.array([-1, -2, -3, 4, 5, 6])
np.argmax(arr > 0) # Return (index) 3

At this point, if we can assume (as you seem to imply) that there is a single position of interest (and/or that we only care about the first one, read from left to right) we are done: just decrement one from the answer and you have the other cut-off point (but do check whether we are at a corner case so as not to return a non-valid index).

But in fact, if you can safely assume that the input is sorted, you can avoid doing a linear scan and not even read the whole input. For this, you can do a binary search via searchsorted. Theoretically, this is faster (i.e., logarithmic vs. linear in the worst case) but in practice this will depend on the size of the array. That is, for small enough arrays a linear scan will be faster due to cache locality (or, at least, that should be the case modulo your hardware details).

The optimal algorithm will scan the input array once; indeed, you can show by a standard adversary argument that no faster algorithm exists.

Your current solution does two passes over the input array (the two invocations of np.where) which as stated seems wasteful. Given that we know there's a linear lower bound, the natural question is: how do we solve the problem in a single pass? The answer is to use np.argmax:

import numpy as np
arr = np.array([-1, -2, -3, 4, 5, 6])
np.argmax(arr > 0) # Return (index) 3

At this point, if we can assume (as you seem to imply) that there is a single position of interest (and/or that we only care about the first one, read from left to right) we are done: just decrement one from the answer and you have the other cut-off point (but do check whether we are at a corner case so as not to return a non-valid index).

Your current solution does two passes over the input array (the two invocations of np.where) which as stated seems wasteful. One simple way to solve the problem is to use np.argmax which will take linear time:

import numpy as np
arr = np.array([-1, -2, -3, 4, 5, 6])
np.argmax(arr > 0) # Return (index) 3

At this point, if we can assume (as you seem to imply) that there is a single position of interest (and/or that we only care about the first one, read from left to right) we are done: just decrement one from the answer and you have the other cut-off point (but do check whether we are at a corner case so as not to return a non-valid index).

But in fact, if you can safely assume that the input is sorted, you can avoid doing a linear scan and not even read the whole input. For this, you can do a binary search via searchsorted. Theoretically, this is faster (i.e., logarithmic vs. linear in the worst case) but in practice this will depend on the size of the array. That is, for small enough arrays a linear scan will be faster due to cache locality (or, at least, that should be the case modulo your hardware details).

Source Link
Juho
  • 3.6k
  • 20
  • 18

The optimal algorithm will scan the input array once; indeed, you can show by a standard adversary argument that no faster algorithm exists.

Your current solution does two passes over the input array (the two invocations of np.where) which as stated seems wasteful. Given that we know there's a linear lower bound, the natural question is: how do we solve the problem in a single pass? The answer is to use np.argmax:

import numpy as np
arr = np.array([-1, -2, -3, 4, 5, 6])
np.argmax(arr > 0) # Return (index) 3

At this point, if we can assume (as you seem to imply) that there is a single position of interest (and/or that we only care about the first one, read from left to right) we are done: just decrement one from the answer and you have the other cut-off point (but do check whether we are at a corner case so as not to return a non-valid index).