Start with an array A of positive numbers. Start at index 0. From index i, you can move to index i+x for any x <= A[i]. The goal is to find the minimum number of moves needed
Here's a slight modification of Ricky Bobby's answer, which I'll show to be optimal:
find_shortest_path(A):
path := [0]
last := 0
max_reachable = 0
while A[last] + last < length(A) :
next_hop := x such that max_reachable < x <= A[last] + last and last + A[x] is maximum
push(path, x)
max_reachable = A[last] + last
last := x
return path
proof of correctness: I'll use induction the nodes of the path created by my algorithm.
the property I'll show is P(i) = the ith node of my path has a 'reach' no smaller than the ith node of any optimal path
where reach is defined as the number of the highest node you can hop to from that node, or +infinity if you can get past the end of the array
P(0) is obvious.
assume that P(k) is true for k >= 0
now consider the (k + 1)th node in the path created by my algorithm. Since my algorithm chose node k so that it had at least the same reach as that of the optimal path's node k, the set of nodes which may possibly be the (k + 1)th node for my algorithm is a superset of the same for any optimal path. Since my algorithm chooses the node with the greatest reach, it follows that P(K + 1) is true.
by induction, P(k) is true for all k (up to the size of the path created).
since my algorithm will end as soon as the end of the array is in reach, and this will happen no later than for any optimal path, it follows that the path created by my algorithm is optimal.
proof of optimality: each cell of the array is considered at most once, so it's O(n), which is asymptotically optimal. I don't think it's possible to design an algorithm which checks fewer cells in every case.
Since you can chose any x in [1,A[i]] I guess there is a pretty simple solution :
start at 0:
select the next reachable element from which you can reach the farther element. i.e chose i that maximize i+A[i+x] for x in [1,A[i]]
until you arrive at the end of the list.
Example:
{2 , 4 , 1 , 2 , 3 , 2 , 4 , 2}
start at 0
from 0 you can get to 1 or to 2:
therefore max(0+A[0+x]) is for i = 1
chose 1 from 1 you can get to 2 3 4:
therefore max(1+A[1+x]) is for i = 4
chose 4
you can reach 7
stop
the resulting list is :
0,1,4,7
As explained in my comments I think it's O(N), because from i you reach i+x+1 in at least 2*x operations.
'Pseudo' proof
You start at 0 (it's optimal)
then you select i that maximize(0+A[0+x]) (i.e that maximize the reachability for the next element)
from that i you can reach any other element that is reachable from all other elements reachable from 0 (it's a long sentence, but it means : who can do more, can do less, therefore if i is not optimal,it's as good as optimal)
So i is optimal
then following step by step this reasoning, it proves the optimality of the method.
If someone knows how to formulate that more mathematically, feel free to update it.
My method:
Create an array reqSteps to store the number of moves an input takes to escape.
Start from the end of the array.
Check if input[i] can escape the array by itself, if yes enter 1 in minSteps, if no, store the minimum of successive input[i] values + 1.
Result is minSteps[0];
The top method does not work for the input{ 10, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1 };
It will give 9 as the answer.
Correct answer is 2.
public static void arrayHop()
{
int[] input = { 10, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1 };
int length = input.length;
int answer = calcArrayHop(input, length);
}
public static int calcArrayHop(int[] input, int length) {
int minSteps;
int[] reqSteps = new int[length];
for(int i=0;i<length;i++)
reqSteps[i]=Integer.MAX_VALUE;
int nextStep;
for (int i = length - 1; i >= 0; i--) {
int minsteps = Integer.MAX_VALUE;
if (i + input[i] >= length) {
reqSteps[i] = 1;
} else
{
for (int j = i+1; j <= (i + input[i]); j++) {
if(j>input.length-1)
break;
if (reqSteps[j] < minsteps)
minsteps = reqSteps[j];
}
reqSteps[i] = minsteps+1;
}
}
return reqSteps[0];
}
}
I'll go against the flow and tell you that your algorithm is "perfect".
It uses dynamic programming in its cleanest form, and its complexity is not so bad. In this sense, I'd say it is likely to be what was expected from you at the interview.
If you have a bound on the entries (say A[i] <= C(N)), then its complexity is O(N * max(C(N), N)). For instance, if all the entries are less than K, it is O(N).
Using Dijkstra's algorithm (or more generally reducing the problem to a shortest path problem) is smart, but I rank it behind the clean DP solution, since graph algorithms are complex (and it could backfire at an interview if you were asked about them).
Note that Dijkstra would be O(N C(N) + N log N) instead (N vertices, and N C(N) edges). So depending on C, you are either strictly better or equal in complexity.