Searching in a Sorted and Rotated Array

Searching in a sorted and rotated array

This can be done in O(logN) using a slightly modified binary search.

The interesting property of a sorted + rotated array is that when you divide it into two halves, atleast one of the two halves will always be sorted.

Let input array arr = [4,5,6,7,8,9,1,2,3]
number of elements = 9
mid index = (0+8)/2 = 4

[4,5,6,7,8,9,1,2,3]
^
left mid right

as seem right sub-array is not sorted while left sub-array is sorted.

If mid happens to be the point of rotation them both left and right sub-arrays will be sorted.

[6,7,8,9,1,2,3,4,5]
^

But in any case one half(sub-array) must be sorted.

We can easily know which half is sorted by comparing start and end element of each half.

Once we find which half is sorted we can see if the key is present in that half - simple comparison with the extremes.

If the key is present in that half we recursively call the function on that half

else we recursively call our search on the other half.

We are discarding one half of the array in each call which makes this algorithm O(logN).

Pseudo code:

function search( arr[], key, low, high)

mid = (low + high) / 2

// key not present
if(low > high)
return -1

// key found
if(arr[mid] == key)
return mid

// if left half is sorted.
if(arr[low] <= arr[mid])

// if key is present in left half.
if (arr[low] <= key && arr[mid] >= key)
return search(arr,key,low,mid-1)

// if key is not present in left half..search right half.
else
return search(arr,key,mid+1,high)
end-if

// if right half is sorted.
else
// if key is present in right half.
if(arr[mid] <= key && arr[high] >= key)
return search(arr,key,mid+1,high)

// if key is not present in right half..search in left half.
else
return search(arr,key,low,mid-1)
end-if
end-if

end-function

The key here is that one sub-array will always be sorted, using which we can discard one half of the array.

Searching a number in a rotated sorted Array

The solution still works out to a binary search in the sense that you'll need to partition the array into two parts to be examined.

In a sorted array, you just look at each part and determine whether the element lives in the first part (let's call this A) or the second part (B). Since, by the definition of a sorted array, partitions A and B will be sorted, this requires no more than some simple comparisons of the partition bounds and your search key.

In a rotated sorted array, only one of A and B can be guaranteed to be sorted. If the element lies within a part which is sorted, then the solution is simple: just perform the search as if you were doing a normal binary search. If, however, you must search an unsorted part, then just recursively call your search function on the non-sorted part.

This ends up giving on a time complexity of O(lg n).

(Realistically, I would think that such a data structure would have a index accompanying it to indicate how many positions the array has been rotated.)

Edit: A search on Google takes me to this somewhat dated (but correct) topic on CodeGuru discussing the same problem. To add to my answer, I will copy some pseudocode that was given there so that it appears here with my solution (the thinking follows the same lines):

Search(set):
if size of set is 1 and set[0] == item
return info on set[0]
divide the set into parts A and B
if A is sorted and the item is in the A's range
return Search(A)
if B is sorted and the item is in the B's range
return Search(B)
if A is not sorted
return Search(A)
if B is not sorted
return Search(B)
return "not found"

What am I doing wrong in this question- Search in Rotated Sorted Array...?

You can use binary-search but you need to consider that the array of the problem is not sorted (sorted but rotated) and you need to find the sorted part of the array on the left or right of middle.

class Solution:
def search(self, arr, x):

l=0
u=len(arr)-1
m=0

while l<=u :
m = l+(u-l)//2

if arr[m] == x :
return m

elif arr[m] >= arr[l] :

# sorted part is left-side of middle
if x >= arr[l] and x < arr[m]:
u = m-1

# sorted part is right-side of middle
else:
l = m+1
else:

# sorted part is right-side of middle
if x <= arr[u] and x > arr[m]:
l = m+1

# sorted part is left-side of middle
else:
u = m-1
return -1

Check:

>>> Solution().search([4,5,6,7,0,1,2], 0)
4

>>> Solution().search([4,5,6,7,0,1,2], 3)
-1

>>> Solution().search([1], 0)
-1

Binary search to find the rotation point in a rotated sorted list

A slight modification on the binary search algorithm is all you need; here's the solution in complete runnable Java (see Serg's answer for Delphi implementation, and tkr's answer for visual explanation of the algorithm).

import java.util.*;
public class BinarySearch {
static int findMinimum(Integer[] arr) {
int low = 0;
int high = arr.length - 1;
while (arr[low] > arr[high]) {
int mid = (low + high) >>> 1;
if (arr[mid] > arr[high]) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
public static void main(String[] args) {
Integer[] arr = { 1, 2, 3, 4, 5, 6, 7 };
// must be in sorted order, allowing rotation, and contain no duplicates

for (int i = 0; i < arr.length; i++) {
System.out.print(Arrays.toString(arr));
int minIndex = findMinimum(arr);
System.out.println(" Min is " + arr[minIndex] + " at " + minIndex);
Collections.rotate(Arrays.asList(arr), 1);
}
}
}

This prints:

[1, 2, 3, 4, 5, 6, 7] Min is 1 at 0
[7, 1, 2, 3, 4, 5, 6] Min is 1 at 1
[6, 7, 1, 2, 3, 4, 5] Min is 1 at 2
[5, 6, 7, 1, 2, 3, 4] Min is 1 at 3
[4, 5, 6, 7, 1, 2, 3] Min is 1 at 4
[3, 4, 5, 6, 7, 1, 2] Min is 1 at 5
[2, 3, 4, 5, 6, 7, 1] Min is 1 at 6

See also

  • Java Collections.rotate() with an array doesn’t work

    • Explains why Integer[] instead of int[]
  • Google Research Blog: Nearly All Binary Searches and Mergesorts are Broken

    • Explains why >>> 1 instead of / 2

On duplicates

Note that duplicates makes it impossible to do this in O(log N). Consider the following bit array consisting of many 1, and one 0:

  (sorted)
01111111111111111111111111111111111111111111111111111111111111111
^

(rotated)
11111111111111111111111111111111111111111111101111111111111111111
^

(rotated)
11111111111111101111111111111111111111111111111111111111111111111
^

This array can be rotated in N ways, and locating the 0 in O(log N) is impossible, since there's no way to tell if it's in the left or right side of the "middle".


I have one another condition. What if the list is not sorted??

Then, unless you want to sort it first and proceed from there, you'll have to do a linear search to find the minimum.

See also

  • Wikipedia | Selection algorithm | Linear minimum/maximum algorithms

Search in Rotated Sorted Array Leetcode

You'll have to think on some modification in the binary search approach because binary search approach is applicable only for sorted array.

Hint : Think about finding some subarrays (which are sorted) and then apply binary search only on those specific parts.

Currently, you are not comparing a[low] & a[mid]. Only if you compare these two array indices, you'll get an idea of how the array elements are in the subarray (increasing or decreasing).

You are comparing a[low] & a[mid] with your target element , which will not output the desired relation of subarray(increasing or decreasing)



Related Topics



Leave a reply



Submit