Finding the magic index in array, A
Problem
A magic index in an array A [0. . .n-1] is defined to be an index such that A[i]
= i. Given a sorted array of distinct integers, write a method to find a magic
index, if one exists, in array A.
FOLLOW UP
What if the values are not distinct?
Answer
This is another question I found interesting in the Cracking coding interview book.
Brute-force approach, $O(N)$
The simplest way to solve this problem is to scan the array, A from A[0] to A[N-1] looking for the index, i where A[i] = i.However, this wouldn't be the answer to this question. This means the question is asking for a faster algorithm than $O(N)$. Possible $O(\log N)$ ?
Recursive Binary search approach, $O( \log N)$
Let's draw out the example array with the magic index at 3 with the size of 5. It would be like the below:Figure 1. Example input |
This gives enough information to perform the binary search following the algorithm below
Given, chosen half, h,
case 1) if A[h] == h, found the magic index
case 2) if A[h] > i, search the right size of index, h
case 3) if A[h] < i. search the right size of index, h
This algorithm will run in $O(\log N)$
If the values are not distinct, binary search will not work since both left and right sides of the magic index can have integers either greater than the index or less than the index.
Update (05.06.2016):
Initially, I thought only linear scanning will work if there are duplicate keys. However, I later realized that we can still perform the recursive search, which is marginally better than the linear scanning depending on the combination of the integers in the array.
Take the look at Figure 2, which presents array A, with duplicate integers.
Figure 2. For example case of duplicate integers, there are two magic indexes |
It is a major setback. However, there is the still a room for improvement. We should now search both sides of the array each time but we can still reduce the scope to search based on the following rules.
Given start, the starting position, and end the end position, the h, index splitting the array in half and A[h] the value in that position,
Rule 1) For the left side of the array, we now know that index h can't be the magic index anymore.
In choosing the new end index for search, we can choose the minimum of h-1 and A[h].
Therefore, we search between start and Min(h-1, A[h])
Rule 2) For the right side of the array, we also know that index h can't be the magic index anymore.
In choosing the new start index for search, we can choose the maximum of h-1 and A[h].
Therefore, we search between Max(h-1, A[h]) and end
UPDATE(2022-06-24): This algorithm can't work if the negative values are allowed in the array. This is only valid if only non-negative values are in the array.
I would say the expected running time is faster than $O(N)$ since it is not guaranteed that we can reduce the search space each time considerably.
However, it will be faster than the linear search in practice.
The following code is modified to apply the two rules explained above.
Practice statistics
19:23: to write up the code
08:48: to realize the second question is for $O(N)$
** April 28 2019: Tried again in Python. Here is a solution in Python
Practice statistics
21 mins: to write up the code
5 mins to write up the answer to the second question is for $O(N)$
UPDATE(2022-06-24): Solved the problem again with the binary search with the distinct flag as a parameter to denote the condition for the duplicate values in the array.
10:22: to write up the code
03:58: to review the code.
Comments
Post a Comment