Problem Statement
Given an array a[]
that is sorted, but after sorting, some elements are moved to either of the adjacent positions, i.e., a[i]
may be present at a[i+1]
or a[i-1]
.
Write an efficient algorithm to search for a target
value in this array. Note that, the element a[i]
can only be swapped with either a[i+1]
or a[i-1]
.
For example consider the array {2, 3, 10, 4, 20}
, where 4
is moved to next position and 10
is moved to previous position.
Example 1:
Input: arr[] = {10, 3, 40, 20, 50, 80, 70}, target = 40
Output: 2
Output is index of 40 in the given array
Example 2:
Input: arr[] = {10, 3, 40, 20, 50, 80, 70}, target = 90
Output: -1
-1 is returned since the target value is not found
Binary Search to find an element in a nearly (almost) sorted array
Given that the array is sorted but an element can be moved to its adjacent positions, we can apply binary search with some tweaks to search for the target
value in O(log n)
time complexity:
- First, compare the
target
value with all the 3 elements in the middle (since the middle element can be swapped with its adjacent elements). If thetarget
is equal to any of the middle 3 elements, then we return the corresponding index. - Otherwise, if
target < a[mid]
, then we can discard the upper half of the array and continue the search in the lower half by settingend=mid-2
. This is because all the elements aftermid+2
(upper half of the array) will be greater thana[mid]
so no point searching fortarget
in the upper half. - If
target > a[mid]
, then continue the search in the upper half of the array by settingstart=mid+2
. (All the elements beforemid-2
will be smaller thana[mid]
so we can discard the lower half of the array)
Let’s look at the implementation:
import java.util.Scanner;
class SearchInNearlySortedArray {
private static int binarySearchNearlySorted(int[] a, int target) {
int n = a.length;
int start = 0;
int end = n-1;
while(start <= end) {
int mid = (start + end)/2;
if(target == a[mid]) {
return mid;
}
if(mid > 0 && target == a[mid-1]) {
return mid-1;
}
if(mid < n-1 && target == a[mid+1]) {
return mid+1;
}
if (target < a[mid]) {
end = mid-2;
} else {
start = mid+2;
}
}
return -1;
}
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int n = keyboard.nextInt();
int[] a = new int[n];
for(int i = 0; i < n; i++) {
a[i] = keyboard.nextInt();
}
int target = keyboard.nextInt();
keyboard.close();
System.out.printf("BinarySearchNearlySorted(%d) = %d%n", target, binarySearchNearlySorted(a, target));
}
}
# Output
$ javac SearchInNearlySortedArray.java
$ java SearchInNearlySortedArray
7
10 3 40 20 50 80 70
40
BinarySearchNearlySorted(40) = 2
$ java SearchInNearlySortedArray
7
10 3 40 20 50 80 70
90
BinarySearchNearlySorted(90) = -1