7

Suppose I have an array a[i] for 0<=i<=n-1. Can I find, using an algorithm of complexity O(log n), i such that 1<=i<=n-2, a[i]<=a[i+1] and a[i]<=a[i-1]? That is, can I find a local minima in logarithmic time?

Note: I edited the question (which had changed many times) to be one that could reasonably be answered. I removed the strange end conditions that appeared in an earlier version because this version is simpler and yet loses no generality.

Michael Pryor
  • 25,046
  • 18
  • 72
  • 90
user1575207
  • 103
  • 1
  • 4

7 Answers7

6

First, we need to consider how a local minimum is defined:

a[i] < a[i-1] and a[i] < a[i+1]

From this condition, we see that if we were to plot the array on an X/Y graph (X=index, Y = value), local minimums would be at the valleys. Therefore, to ensure there is a local minimum, we must guarantee that a change in slope sign (from decreasing to increasing) exists.

If you know the endpoint slope behavior of a range, you know if there is a local minimum within. In addition, your array must have the behavior decreasing slope sign from a[0] to a[1] and increasing slope sign from a[n-1] to a[n] or the problem is trivial. Consider:

a = [1,2,3,4,5] (increasing, increasing) a[0] is an LM
a = [5,4,3,2,1] (decreasing, decreasing) a[n] is an LM
a = [1,2,2,2,1] (increasing, decreasing) a[0] and a[n] are LMs

I think this should be enough inspiration for you to complete the method.

Note that expanding this method is good only for unique values, for example an array of all 1s, it will not have O(log n) run time unless you do some edge case detection.

Calvin Jia
  • 856
  • 5
  • 5
3

Unless your array has other constraints on it, you can't find local minimum in O(log n) without (at least) linear time preprocessing, because in worst case you need to check every single element in your array. It is not difficult to prove this statement formally, the idea is to construct such array, for each scanning method, that this method will work in linear time on constructed array.

For example, imagine if you're doing simple scan in array of size n from the beginning to the end: if your minimum is at n-1-th position, then you'll discover it only after n-1 iterations, which is O(n)

http://www.careercup.com/question?id=8223978

user1543957
  • 1,758
  • 4
  • 20
  • 30
Alexander Putilin
  • 2,262
  • 2
  • 19
  • 32
  • Actually OP may be looking for something like en.wikipedia.org/wiki/Ternary_search . If an array either have exactly one local optimum, or it is sorted(doesn't matter ascending or descending), you can find local optimum in O(log n). – Alexander Putilin Aug 03 '12 at 22:10
1

It is solved with similar to binary search approach in O(log n), but only in case when you have one local minimum and distinct numbers in array. Your array must be something like the following:

8 5 4 3 [1] 2 6 9

One is local minimum here.

Check bounds. if a[0] < a[1], a[1] is an local minimum. if a[n-1] > a[n], a[n] is an local minimum. If none of these conditions not true - begin dividing:

Check a[n/2], if a[n/2] > a[n/2 + 1] then local minimum in right side of array, otherwise in left side. After that solving problem recursively.

mishadoff
  • 10,719
  • 2
  • 33
  • 55
  • 1
    If we reorder your array as "6 8 [1] 5 9 4 3 2 6". We take n/2 which is 9, its > 4 so we'd recurse on right but the local minimum is on the left. – Colin Jack Jul 29 '13 at 15:52
  • the question just asks us to find one local minimum and in your case, the algorithm should give `"6 8 1 5 9 4 3 [2] 6"` – Ray Oct 05 '14 at 08:29
0

I am not able to disprove the working of this solution, so I would be happy if somebody could.

Consider array 'a' indexed from 1 to n.

low = 1
high = n
mid = (low + high)/2

Without loss of too much generality, I am going to assume the array values are distinct. So,at mid, the a[mid - 1], a[mid], a[mid + 1] can be like:

Case 1:

/\


Case 2:

\/

Case 3:

 / 
/

Case 4:

 \
  \

Case 5(boundary):
/

Case 6(boundary):
\

&m = mid

Each case can be checked using if conditions as follows:

1: a[m] > a[m-1] && a[m] > a[m+1]
2: a[m] < a[m-1] && a[m] < a[m+1]
3: a[m] > a[m-1] && a[m] < a[m+1]
4: a[m] < a[m-1] && a[m] > a[m+1]

I am also going to ignore explaining the boundary cases:

The 2nd case is the desired case where a[m] is the local minima

for the 3rd case:

there is always a local minima is to the left, so, set h = m - 1 and continue

for the 4th case:

there is always a local minima to the right, so, l = m + 1 and continue

for the 1st case, I can go on either direction: I believe this works because the only time you reduce the segment you are considering is when you are sure there is a local minima in the reduced segment, so the segement you search will always have some local minima.

Note: This will work only to find a single local minima and not every local minima. The latter case would require O(n) since you definitely have to see the whole array at least once.

0

The problem can be solved in O(logn) by using a kind of binary search.

The trick is explained very well in http://www.dsalgo.com/2013/03/find-local-minima-in-array.html. That website provided a recursive implementation.

I actually came up with another iterative implementation as follows.

#include <cstdio>
#include <vector>
using std::vector;

int SearchLocalMinima(const vector<int>& sspace) {
        if (sspace.size() < 2)
                return -1;
        if (sspace.size() == 2)
                return 0;
        int L = 0, U = sspace.size() - 1;
        while (L<U) {
                int M = L + (U - L) / 2;
                if (M - 1 == L) {
                        if (sspace[M] <= sspace[M + 1])
                                return M;
                        else
                                return M + 1;
                } else {
                        if (sspace[M] <= sspace[M + 1])
                                U = M + 1;
                        else
                                L = M;
                }

        }
        return -1;
}

int main() {
        vector<int> values{64, 14, 52, 27, 71, 19, 63, 1, 16, 57};
        printf("Local minima: %d\n", SearchLocalMinima(values));
        return 0;
}

Output: Local minima: 7

Duke
  • 1,332
  • 12
  • 12
-1

Edit: This works only if the local minimum is defined by "<=", not "<". However, with "<" there is no solution. So I'll keep this here, with the note that it doesn't solve the (unsolvable) question of the OP.


The following divide-and-conquer method should find a local minimum in O(log n), if at least one local minimum exists.

  1. Consider the first, last and middle element (lets call them A, B, C).
  2. If A is the least of the three, continue with the first half of your array.
  3. Otherwise, if C is the least of the three, continue with the second half of your array.
  4. Otherwise, (ie. B is the least of the three), check if the middle element of the first half (D) is lower than B, and use the left half in that case.
  5. Otherwise, check if the middle element of the right half (E) is lower than B, and use the second half in that case.
  6. Otherwise, continue with the elements from D to E (where B is in the middle).

In each of the cases 2. - 6. you continue with an element that has higher elements to the left and to the right (although not necessarily directly), or is at the border. Each time the number of elements to consider is halved, so it's O(log n). In the end you consider only 3 elements or less, and the minimal number of these is a local minimum.

Reinstate Monica
  • 4,568
  • 1
  • 24
  • 35
-2

I'm assuimg this is a homework question, so I am answering appropriately. You must be given a starting position if you are searching for a local minimum because you need a reference for what is "local." If the element to the left is less than that element, go to that element and try again. Otherwise, if the element to the right is less than current, go right and try again. Otherwise, the current element is a local min.

EDIT: The requirement for O(log n) time was added after I read the question. I will think about a solution meeting this requirement.

Another EDIT: I do not think that this is possible in the time requirement of O(log n) for an unsorted array because there is no way to divide the problem in half. On the other hand, there is a trivial O(1) solution for a sorted array :)

Daniel
  • 6,595
  • 9
  • 38
  • 70
  • What is considered "local" is defined in question. // It's not me, who downvoted ;-) – kirilloid Aug 03 '12 at 21:42
  • @kirilloid I know it is, but there can be many local minima and you need a reference point to figure out which one you are looking for. – Daniel Aug 03 '12 at 21:43