3

I have given this a lot of thought and was unable to find the most optimal solution. I am preparing for technical interviews, but I haven't found very much stuff related to this question. My first step was to implement a naive O(n) algorithm that searches through the entire array to find the maximum integer. Now I know I can do much better than this, so I thought maybe there was a way to use Binary Search or take advantage of the fact that at least one half of the array is fully sorted. Maybe you could find the middle value and compare it to the start and end of the array.

Example:

[5, 7, 11, 1, 3] would return 11.

[7, 9, 15, 1, 3] would return 15.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
user2351234
  • 965
  • 2
  • 12
  • 20
  • Ok, so continue your train of thought. Answering interview questions is not about knowing the answer, it's about solving a problem. – Oliver Charlesworth Jan 13 '15 at 23:43
  • look at this:http://stackoverflow.com/questions/1878769/searching-a-number-in-a-rotated-sorted-array – qqibrow Jan 13 '15 at 23:46
  • 1. find the smallest value. 2. return the value on the left. – Ivan Kuckir Jan 13 '15 at 23:49
  • I think the optimal complexity is O(log(n)). Read first, middle and last value. If first – Ivan Kuckir Jan 13 '15 at 23:54
  • 2
    Your first array doesn't appear to meet the criteria. The array is supposed to be an array that is sorted and then possibly rotated, right? The "sorted" array in this case would be `[1, 5, 7, 6, 4, 10, 11]`, which isn't sorted--right? Or am I misunderstanding the question? If I'm misunderstanding it, I think you need to explain better what the constraints on the array are. – ajb Jan 13 '15 at 23:54
  • OK, instead of giving a complete answer, I'll give the start of one. Split the array in two parts. If the number to the left of the split is greater than the number to the right of the split, then [fill in]. Otherwise, look at the first and last numbers of each of the two subarrays (up to four numbers). The greatest number will be in one of those subarrays; how can you tell which one? – ajb Jan 14 '15 at 00:03
  • @OliverCharlesworth: deleting my earlier answer because I apparently misunderstood the question. Would you say then that, given these parameters, (n log n) is about the best that can be hoped for in this case? – frasnian Jan 14 '15 at 00:13
  • @frasnian: There's a log(n) solution. – Oliver Charlesworth Jan 14 '15 at 00:14
  • @OliverCharlesworth: but wouldn't that be post-sort? – frasnian Jan 14 '15 at 00:15
  • @frasnian: No, you can find a condition that allows you to recursively divide the array toward the maximum. – Oliver Charlesworth Jan 14 '15 at 00:17
  • @OliverCharlesworth: Then I would love to see this posted as an answer. What is the "maximum"? That *in itself* is O(n). So, where from there? Not disputing you - I can use this. If it exists. Otherwise, you are talking about a simple binary partition (search). What am I missing? – frasnian Jan 14 '15 at 00:31
  • @OliverCharlesworth: just read (as in past-tense, not "you should") the question more carefully. So, we are already given "sorted" -- my bad. On edit: it's been a *long* day. – frasnian Jan 14 '15 at 00:53

8 Answers8

4

In a sorted array (even rotated), you can be sure to use binary search (O(log2(n)).


/**
* Time complexity: O(log2(n))
* Space complexity: O(1)
*
* @param nums
* @return
*/
public int findMax(int[] nums) {
        // binary search
        int left = 0;
        int right = nums.length - 1;

        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[left] < nums[mid]) {
                left = mid;
            } else if (nums[left] > nums[mid]) {
                right = mid - 1;
            } else {    
                // subtility here if there are duplicate elements in the array.
                // shift the left linearly
                left = left + 1;
            }
        }
        return nums[left];
    }
Raymond Chenon
  • 11,482
  • 15
  • 77
  • 110
1

You have to binary search in a clever way to achieve a O(lg n) bound. Observe that the element to the right of the max element is the min (or none if the array is not rotated at all). So do a regular binary search but check that the element at index mid is the max, if not compare the first and last elements in each of the left/right subarrays. If first<last in the left subarray, you know that the left subarray is sorted and go right, otherwise you go left.

Let's assume that array is called a and it has n elements.

/* check if not rotated at all */
int ans = INFINITY;
if(a[0] < a[n-1] || n == 1)
{   ans = a[n-1];
    return;
}

/* array is certainly rotated */
int l = 0, r = n-1;
while(r - l > 5)
{   int m = (l + r) / 2;
    if(a[m] > a[m+1]) { ans = a[m]; break; }
    else
    {   if(a[l] < a[m-1]) l = m+1;
        else r = m-1;
    }
}

/* check the remaining elements (at most 5) in a loop */
if(ans == INFINITY)
{   for(int i = l; i <= r; i++)
    {   ans = max(ans, a[i]);
    }
}

I've not tested this code. The reason i break when the number of elements is 5 or less is to be sure that number of elements in either subarray is at least 2 (so you can be sure that first and last are not the same element). You've got to try this yourself and fix it if there is anything to fix. Hope this helps.

mrk
  • 3,061
  • 1
  • 29
  • 34
  • I think it's the correct answer but why check the "not rotated" case explicitly? isn't it included in the bsearch part? – shole Jan 14 '15 at 01:18
  • I did not test the code, it might be the case that this piece of code is redundant but it's a constant amount of work anyway. – mrk Jan 14 '15 at 01:20
1

Use modified binary search to eliminate half the sorted subarray (if there are two sorted subarrays remove the "lower" subarray) in each step while keeping track of a potentially updated maximum.

#include <iostream>
#include <cstdlib>
#include <vector>

int main(int argc, char** argv)
{   
    std::vector<int> nums;
    for(int i = 1; i < argc; i++)
        nums.push_back(atoi(argv[i]));

    int start = 0;
    int end = argc - 2;
    int max = nums[start];
    while(start <= end) {
        int mid = (start + end) >> 1;
        int cand;
        if(nums[start] <= nums[mid])  {
            start = mid + 1;
        } else {
            end = mid - 1;
        }
        cand = nums[mid];
        if(cand > max)
           max = cand;
    }
    std::cout << max << std::endl;
    return 0;
}
ssh
  • 195
  • 1
  • 11
1

Leetcode accepted answer

Condition - (array is sorted, it is rotated) -

Searching for a max element in sorted rotated array in a long length array is little bit easy but we have to consider the edge cases which are the reason why maximum code answers fail at end. Approach is similar to binary search but edge cases are different

Case 1: when array is of size 2. we can directly return max or min element from the array.

Case 2: When we return our start index, we should always double check if it is greater than the start+1 element as when we return start index we usually increase it by size one and it returns the element which is not the greatest.

Code for this:

public static int findMax(int[] nums) {
        // binary search
        int start = 0;
        int end = nums.length - 1;
        // if array length is 2 then directly compare and return max element
        if(nums.length == 2){
            return nums[0] > nums[1] ? 0 : 1;
        }

        while (start < end) {
            // finding mid element
            int mid = start + (end - start) / 2;
            // checking if mid-element is greater than start
            // then start can become mid
            if (nums[start] < nums[mid]) {
                start = mid;
            }
            // checking if mid-element is smaller than start
            // then it can be ignored and end can become mid-1
            else if (nums[start] > nums[mid]) {
                end = mid - 1;
            }
            // now checking the edge case
            // we have start element which is neither smaller or greater than mid 
            // element
            // that means start index = mid-index
            // so we can increase start index by 1 if current start index is smaller 
            // that start +1
            // else the current start index is the max element
            else {
                if(nums[start]<=nums[start+1]) {
                    start = start + 1;
                }
                else {
                    return nums[start];
                }
            }
        }
        return nums[start];
    }

#binarySearch #rotatedArray #sortedArray #array

0

Question : find largest in the rotated sorted array.The array don't have any duplicates: Solution : Using Binary Search. The Idea : Always remember in a Sorted Rotated Array, the largest element will always be on the left side of the array. Similarly, the smallest element will always be on the right side of the array. The code is :

public class Test19 {

    public static void main(String[] args) {
        int[] a = { 5, 6, 1, 2, 3, 4 };
        System.out.println(findLargestElement(a));

    }

    private static int findLargestElement(int[] a) {

        int start = 0;
        int last = a.length - 1;

        while (start + 1 < last) {

            int mid = (last - start) / 2 + start;
            if (mid < start) {
                mid = start;
            }
            if (mid > start) {
                last = mid - 1;
            } else {
                mid--;
            }

        } // while

        if (a[start] > a[last]) {
            return a[start];
        } else
            return a[last];

    }

}
Soudipta Dutta
  • 1,353
  • 1
  • 12
  • 7
0

The solution I've come up with is both compact and efficient. It is basically a spin-off of the Binary Search Algorithm.

int maxFinder(int[] array, int start, int end)
  {
    //Compute the middle element
    int mid = (start + end) / 2;

    //return the first element if it's a single element array
    //OR
    //the boundary pair has been discovered.
    if(array.length == 1 || array[mid] > array[mid + 1])
    {return mid;}

    //Basic Binary Search implementation
    if(array[mid] < array[start])
    {return maxFinder(array, start, mid - 1);}
    else if(array[mid] > array[end])
    {return maxFinder(array, mid + 1, end);}

    //Return the last element if the array hasn't been rotated at all.
    else
    {return end;}
  }
  • The above program works with both single element arrays and arrays with duplicate elements. –  Jul 31 '20 at 15:16
  • { 0, 0, 1, 0 }? This returns the index: have a look at the example in the question. – greybeard May 08 '21 at 04:38
0

Speaking of using binary search to solve this problem at a time complexity of O(log2n). I would do as the following

#include<stdio.h>
#define ARRSIZE 200 
int greatestElement(int* , int ) ;

int main()  {
    int arr[ARRSIZE] ; 
    int n ; 
    printf("Enter the number of elements you want to enter in the array!") ;
    scanf("%d" , &n) ;
    printf("Enter the array elements\n") ;
    for(int i = 0 ; i < n ; i++)    {
        scanf("%d", &arr[i]) ;
    }
    printf("%d is the maximum element of the given array\n",greatestElement(arr,n)) ;
}

int greatestElement(int* arr, int n)    {
    int mid = 0 ;
    int start = 0 , end = n-1 ;
    while(start < end)  {
        mid = (start+end)/2 ;
        if(mid < n-1 && arr[mid] >= arr[mid+1]) {
            return arr[mid] ;
        }
        if(arr[start] > arr[mid])   {
            end = mid - 1 ;
        }
        else    {
            start = mid + 1; 
        }
    }
    return arr[start] ;
}```
-1

This question is so easy with another version of binary search:


    int solve(vector<int>& a) {
        int n = a.size();
        int k=0;
        for(int b=n/2; b>=1; b/=2)
        {
            while(k+b<n && a[k+b] >= a[0])
                k += b;
        }
        return a[k];
    }

  • 1
    (Code-only answers are discouraged. The one descriptive identifier I find is `size` - granted, `n` is sort of conventional, `a` too, if for something not quite applying here. Don't write, never publish uncommented/undocumented code. (Try to achieve "`const` correctness".) – greybeard May 08 '21 at 04:30
  • Please add some comments, ideas behind the solution – Xax Jul 31 '21 at 13:12