Interview Question


Country: United States




Comment hidden because of low score. Click to expand.
2
of 2 vote

Find peak element and then divide the array into two sorted arrays.
Apply Binary search to find.
Complexity: O(log n + log a + log b) where a+b=n

- Abhishek Kaushik June 22, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

how about doing it without finding the maximum element ? Any idea..?

- um01 June 22, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

No, u can't because to do this in better than o(n) u need sorted arrays. So definitely u need to find the peak.

- Abhishek Kaushik June 23, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

It can be done without finding the peak, same complexity though. Only takes two binary searches instead of three, however.

Take, as an example, the array {1, 4, 5, 7,,10, 11, 9, 6, -1}
And, while looking for 6 through some variant of binary search, I get the two sub arrays {1,4,5} {7,10,11,9,,6-1}. See if you notice something interesting about the arrays.

- SycophantEve June 24, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@SycophantEve

Let me see if I got this right.

When you do a binary search, you might not find it, so you split up left and right on where your failed binary search is. At this point, if you look at the last two values of the left subarray and first two values of the right sub array, you can figure out which side the peak is on.

In your example. 1,4,5 means the left subarray is increasing which means peak is in the right sub array.

Now when you do the binary search on the right sub array, we can do a modified binary search in that we know there's a peak and two sides but only one side will have possible search because the other side is already bounded when we did the left/right subarray split. So your example 7, 10, 11, 9, 6, -1 ... peak is at 11, but we know the 6 must be on the right side of the peak because when we cut the array in two previously, we know the left side is already greater than 6. So you do a binary search... if the mid value is greater than 6 you binary search right, if a mid value is less than 6 you binary search left (reverse)

Did I get the gist of thing?

- Pete June 24, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@SycophantEve

Let me see if I got this right.

When you do a binary search, you might not find it, so you split up left and right on where your failed binary search is. At this point, if you look at the last two values of the left subarray and first two values of the right sub array, you can figure out which side the peak is on.

In your example. 1,4,5 means the left subarray is increasing which means peak is in the right sub array.

Now when you do the binary search on the right sub array, we can do a modified binary search in that we know there's a peak and two sides but only one side will have possible search because the other side is already bounded when we did the left/right subarray split. So your example 7, 10, 11, 9, 6, -1 ... peak is at 11, but we know the 6 must be on the right side of the peak because when we cut the array in two previously, we know the left side is already greater than 6. So you do a binary search... if the mid value is greater than 6 you binary search right, if a mid value is less than 6 you binary search left (reverse)

Did I get the gist of thing?

- chen.tso June 24, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Pretty much. The idea is, that given any array that is sorted in this way, we can find two things. 1. Which side the peak is on and 2. If we find an element greater than the element we're looking for, then the left side sub array is sorted in increasing order relative to what we're looking for and the right side is sorted in decreasing order relative to what we're looking for.

{1, 4, 5, 7,8, 9,10, 9, 6, -1}

So we check mid = 8
It's greater than 6 so we break up the arrays
{1, 4, 5, 7} {9,10,9,6,-1}.
So even though either array may be unsorted, they still have the invariant required for binary search. In that on the right side, everything that is greater than the element we're looking for is before our element.

Basically you do a binary search, moving closer to the peak each time if the middle element is less than what we're looking for. After we find any element greater than the searched for element, we do a ascending order binary search on the left half and a descending binary searchon the right.

Basically the trick is, the sub arrays are "sorted enough" as long as you split at an element > than the search for element.

In the example above, you also notice that the right array is "sorted enough".

- SycophantEve June 24, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Use binary search.

- Anonymous June 22, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Find max element with binary search. Then do binary search on the subarray of all numbers to the left of the max, then do another binary search on subarray on all numbers to the right of the max.

log(n) for max
log(n/2) for left subarray
log(n/2) for right subarray

-> 3log(n) time -> O(logn)

- SK June 22, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Nice approach. However, I don't think the time calculation is correct since the max element will not always be in the center.

- puneet.sohi June 22, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Array.FindIndex(iArray, w => w==n);

- JJohnston June 22, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Array.FindIndex(iArray, w => w==n);

- jeff johnston June 22, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

As other have already suggested.
1. Do a binary search to find the peak or largest element. O(log n) operation
2. Split the original array at the peak element, say at element p
3. Do a binary search on the lower array. O(log p)
4. Do a binary search on the higher array. O(log n-p)

Complexity = O(log n) + O(log p) + O(log n-p) ~ O(log n).
I'm including some code.

- puneet.sohi June 22, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

//Supporting functions:

int findPeak(int * myArr, int mySize)
{
//Find Peak Element
	if (mySize  == 0 || mySize == 1)
	{
		return 0;
	}

	int h = mySize - 1;
	int l = 0;
	int m = (l + h)/2;

	while(l <= h)
	{
		
		if (l == h)
		{
			cout << "Peak element idx is " << l << endl;
			return l;
		}
		m = (l+h)/2;
		//cout << "low" << myArr[l] << " med" << myArr[m] << " high" << myArr[h] << endl;
		if (myArr[m] > myArr[m-1] && myArr[m] > myArr[m+1])
		{
			cout << "Peak element is at idx" << m << endl;
			return m;
		}
		if(myArr[m] > myArr[m-1])
		{
			//cout << "peak in upper half" << endl;
			l = m+1;
			cout << " l:" << l << endl;
		}
		else
		{
			//cout << "peak in lower half" << endl;
			h = m-1;
			cout << " h: " << h << endl; 
		}
	}
	return 0;
}


bool binarySearch(int *Arr, int start_Idx, int end_Idx, int element)
{
	if (start_Idx > end_Idx)
	{
		cout << "err" << endl;
		return false;
	}
	if (start_Idx == end_Idx)
	{
		if (Arr[0] == element)
		{
			cout << "binarySearch found element at idx 0" << endl;
			return true;
		}
		else
		{
			cout << "binarySearch Not found" << endl;
			return false;
		}	
	}
	int l = start_Idx;
	int h = end_Idx;
	int m = 0;

	while (l <= h)
	{
		m = (l+h)/2;
		//cout << "binarySearch l " << l << " m " << m << " h " << h << endl;
		
		if (Arr[m] == element)
		{
			cout << "binarySearch Found element at idx" << m << endl; 
			return true; 
		}
		else if (Arr[m] > element)
		{
			//cout << "binarySearch Element in lower half" << endl;
			h = m-1;
		}
		else
		{
			//cout << "binarySearch Element in upper half" << endl;
			l = m+1;
		}
	}
	cout << "binarySearch Element not found" << endl; 	
	return false;
}

bool invertedBinarySearch(int *Arr, int start_Idx, int end_Idx, int element)
{
//Binary search for a decreasing array. E.g. {9, 8, 7, 6}
	if (start_Idx > end_Idx)
	{
		cout << "err" << endl;
		return false;
	}
	if (start_Idx == end_Idx)
	{
		if (Arr[0] == element)
		{
			cout << "invertedBinarySearch found element at idx 0" << endl;
			return true;
		}
		else
		{
			cout << "invertedBinarySearch Not found" << endl;
			return false;
		}	
	}
	int l = start_Idx;
	int h = end_Idx;
	int m = 0;

	while (l <= h)
	{
		m = (l+h)/2;
		//cout << "binarySearch l " << l << " m " << m << " h " << h << endl;
		
		if (Arr[m] == element)
		{
			cout << "invertedBinarySearch Found element at idx" << m << endl; 
			return true; 
		}
		else if (Arr[m] > element)
		{
			//cout << "binarySearch Element in lower half" << endl;
			l= m+1;
		}
		else
		{
			//cout << "binarySearch Element in upper half" << endl;
			h = m-1;
		}
	}
	cout << "invertedBinarySearch Element not found" << endl; 	
	return false;
}

- puneet.sohi June 22, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

// Main functions:

void findElement(int *Arr, int size, int element)
{
	if(size == 0)
	{
		cout << "err" << endl;
		return;
	}
	if(size == 1)
	{
		if (Arr[0] == element)
		{
			cout << "Found element at idx 0" << endl;
			return;
		}
		else
		{
			cout << "Not found" << endl;
			return;
		}
	}
	int peak = findPeak(Arr, size);
	int l1 = 0; int h1 = peak;
	int l2 = peak+1; int h2 = size;
	
	if (binarySearch(Arr, l1, h1, element) || invertedBinarySearch(Arr, l2, h2, element))
	{
		cout << "element found" << endl;
	}
	else
	{
		cout << "element not found" << endl;
	}
	return;
}

int main()
{
	int A[9] = {1,2,3,5,7,9,11};
	int B[9] = {11,9,7,5,3,2,1};
	int C[9] = {1,2,5,8,13,9,3,-1};
	findElement(C, 7, 3);
	return 0;
}

- puneet.sohi June 22, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

using modified binary search for no-peak searching
1. get mid item
2.1. if n < a[mid], need to search both side
2.2. n > a[mid], need to decide which side for checking according to its on the increasing slope or decreasing slope

private enum Slope {
		INCREASING, DECREASING, PEAK, INVALID
	}
	
	public static int findNumber(int[] a, int n) {
		return findNumber(a, 0, a.length-1, n);
	}

	private static int findNumber(int[] a, int low, int high, int n) {
		if (low > high)
			return -1;
		
		int mid = (low + high) >> 1;
		//hit it
		if (a[mid] == n)
			return mid;
			
		//there's only one item, missed
		if (low == high)
			return -1;
			
		int result = -1;
		//need to check both side if n < a[mid]
		if (n < a[mid]) { 
			result = findNumber(a, mid+1, high, n);
			if (result != -1)
				return result;
			result = findNumber(a, low, mid-1, n);
			if (result != -1)
				return result;
		} else { //n > a[mid], need to decide which side for checking according to its on the increasing half or decreasing half
			switch(checkSlope(a, mid)) {
				case INCREASING:
					result = findNumber(a, mid+1, high, n);
					break;
				case DECREASING:
					result = findNumber(a, low, mid-1, n);
				case PEAK:
					result = -1;
			}
		}
		return result;
	}
	
	private static Slope checkSlope(int[] a, int mid) {
		if (mid == 0)
			return a[mid+1] > a[mid] ? Slope.INCREASING : Slope.DECREASING;
		
		if (mid == a.length -1)
			return a[mid] > a[mid-1] ? Slope.INCREASING : Slope.DECREASING;
			
		if (a[mid-1] < a[mid] && a[mid] < a[mid+1])
			return Slope.INCREASING;
		
		if (a[mid-1] > a[mid] && a[mid] > a[mid+1])
			return Slope.DECREASING;
		
		if (a[mid-1] < a[mid] && a[mid] > a[mid+1])
			return Slope.PEAK;

		return Slope.INVALID;
	}

- Dancy June 24, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

#include<iostream>
using namespace std;

int getPoint(int arr[], int start, int end, int size)
{
    if(start<end)
    {
        int mid = (start+end)/2;
        if(arr[mid] > arr[mid+1] && arr[mid] > arr[mid-1])
            return mid;
        if(arr[start]<arr[mid] && arr[mid]>arr[end])
            return getPoint(arr, mid+1, end, size);
        else if(arr[start] > arr[mid] && arr[mid] > arr[end])
            return getPoint(arr, start, mid, size);
    }
}

int findVal1(int arr[], int start, int end, int val)
{
    if(start<=end)
    {
        int mid = (start+end)/2;
        //cout<<"  start " <<start<<"  mid = "<<mid<<"  end = "<<end<<endl;
        if(arr[mid]==val)
            return mid;
        else if(arr[mid] > val)
            return findVal1(arr, start, mid-1, val);
        else
            return findVal1(arr, mid+1, end, val);
    }
}


int findVal2(int arr[], int start, int end, int val)
{
    if(start<=end)
    {
        int mid = (start+end)/2;
        //cout<<"  start " <<start<<"  mid = "<<mid<<"  end = "<<end<<endl;
        if(arr[mid]==val)
            return mid;
        else if(arr[mid] < val)
            return findVal2(arr, start, mid-1, val);
        else
            return findVal2(arr, mid+1, end, val);
    }
}

void function(int arr[], int size, int num, int& val)
{
    int pt = getPoint(arr, 0, size, size);
    //cout<<"  pt = "<<pt<<endl;
    if(arr[pt] == num)
        val = pt;
    else if(pt != size && num > arr[pt+1])
    {
        //cout<<"  spot 1"<<endl;
        val = findVal1(arr, 0, pt, num);
    }
    else
    {
        //cout<<"  spot 2"<<endl;
        val = findVal2(arr, pt+1, size, num);
    }
    //cout<<"  Point is :- "<<val<<endl;
}
    
    
int main()
{             // 0  1  2   3   4   5   6   7  8  9  10  11
    int arr[] = {8, 9, 10, 12, 16, 18, 19, 21, 4, 3, 2, -1};
    int size = sizeof(arr)/sizeof(*arr);
    
    cout<<"  Enter value to find :- ";
    int num;
    cin>>num;
    
    int val = -1;
    function(arr, size-1, num, val); 
    
    if(val>=0)
        cout<<"  Result is :- "<<val;
    else
        cout<<"  Not Found "<<endl;
    cout<<endl;    
    system("PAUSE");
    return 0;
}

- skum June 22, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Compilation warnings aside, your getPoint() function is wrong, and consequently the whole algorithm doesn't work.

Counter-example:

Find 6 in [ 6, 20, 15, 12, 11, 10, 9 ].

Hint: getPoint() will mistakenly recurse on array[4..6] looking for the maximum.

- 010010.bin June 22, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@ 010010.bin sry my bad, i thought input as kinda rotated array like:-
a.....Peak.....b, i took all elemnts right of Peak as smaller than a, which isn't the case.
As far as compilation error, i posted the running code (on DevC++) for gcc, need to comment system("PAUSE") .

- skum June 22, 2015 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

You can do this in O(logN) without finding the max... simply apply a binary searh.. compare the middle element(ar[mid]) with ar[mid-1] and ar[mid+1].. this will determine wether ar[mid] is in the increasing part or decreasing part.. now compare the ar[mid] with the "value".. and switch to the other half accordingly..
It may happen that ar[mid] > both ar[mid-1] & ar[mid+1].. at that point simply call the same binarySearch for both the halfs..
Complexity: O(log N).. every time you will divide the array in half...

example: ar = {6, 20, 15, 12, 11, 10, 9}, length = n
search 11: ar[mid] = 12, ar[mid] > ar[mid+1] && ar[mid] < ar[mid -1] .. so it is decreasing sequence... now 11 < ar[mid].. so call the same method for (mid+1 to n)..

Similarly you can search others..

- coderadi June 23, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

with the same example you gave, what if i'm searching for 6? 6 is also smaller than ar[mid], but you won't find 6 at (mid+1, n).

- stephencnca June 24, 2015 | Flag


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More