You are given an integer array arr
. From some starting index, you can make a series of jumps. The (1st, 3rd, 5th, ...) jumps in the series are called odd-numbered jumps, and the (2nd, 4th, 6th, ...) jumps in the series are called even-numbered jumps. Note that the jumps are numbered, not the indices.
You may jump forward from index i
to index j
(with i < j
) in the following way:
j
such that arr[i] <= arr[j]
and arr[j]
is the smallest possible value. If there are multiple such indices j
, you can only jump to the smallest such index j
.j
such that arr[i] >= arr[j]
and arr[j]
is the largest possible value. If there are multiple such indices j
, you can only jump to the smallest such index j
.i
, there are no legal jumps.A starting index is good if, starting from that index, you can reach the end of the array (index arr.length - 1
) by jumping some number of times (possibly 0 or more than once).
Return the number of good starting indices.
Example 1:
Input: arr = [10,13,12,14,15] Output: 2 Explanation: From starting index i = 0, we can make our 1st jump to i = 2 (since arr[2] is the smallest among arr[1], arr[2], arr[3], arr[4] that is greater or equal to arr[0]), then we cannot jump any more. From starting index i = 1 and i = 2, we can make our 1st jump to i = 3, then we cannot jump any more. From starting index i = 3, we can make our 1st jump to i = 4, so we have reached the end. From starting index i = 4, we have reached the end already. In total, there are 2 different starting indices i = 3 and i = 4, where we can reach the end with some number of jumps.
Example 2:
Input: arr = [2,3,1,1,4] Output: 3 Explanation: From starting index i = 0, we make jumps to i = 1, i = 2, i = 3: During our 1st jump (odd-numbered), we first jump to i = 1 because arr[1] is the smallest value in [arr[1], arr[2], arr[3], arr[4]] that is greater than or equal to arr[0]. During our 2nd jump (even-numbered), we jump from i = 1 to i = 2 because arr[2] is the largest value in [arr[2], arr[3], arr[4]] that is less than or equal to arr[1]. arr[3] is also the largest value, but 2 is a smaller index, so we can only jump to i = 2 and not i = 3 During our 3rd jump (odd-numbered), we jump from i = 2 to i = 3 because arr[3] is the smallest value in [arr[3], arr[4]] that is greater than or equal to arr[2]. We can't jump from i = 3 to i = 4, so the starting index i = 0 is not good. In a similar manner, we can deduce that: From starting index i = 1, we jump to i = 4, so we reach the end. From starting index i = 2, we jump to i = 3, and then we can't jump anymore. From starting index i = 3, we jump to i = 4, so we reach the end. From starting index i = 4, we are already at the end. In total, there are 3 different starting indices i = 1, i = 3, and i = 4, where we can reach the end with some number of jumps.
Example 3:
Input: arr = [5,1,3,4,2] Output: 3 Explanation: We can reach the end from starting indices 1, 2, and 4.
Constraints:
1 <= arr.length <= 2 * 104
0 <= arr[i] < 105
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The goal is to figure out how many starting positions let you reach the end by making specific jumps. We're going to try every possible jumping sequence from each starting position to see if it gets us to the end.
Here's how the algorithm would work step-by-step:
def odd_even_jump(array):
number_of_indices_that_reach_end = 0
array_length = len(array)
for start_index in range(array_length):
current_index = start_index
jump_count = 0
can_reach_end = True
while current_index < array_length - 1:
#Determine if we need to make an odd or even jump based on jump count
if jump_count % 2 == 0:
next_index = find_next_odd_jump(array, current_index)
else:
next_index = find_next_even_jump(array, current_index)
if next_index == -1:
can_reach_end = False
break
current_index = next_index
jump_count += 1
if can_reach_end:
number_of_indices_that_reach_end += 1
return number_of_indices_that_reach_end
def find_next_odd_jump(array, current_index):
next_index = -1
min_value = float('inf')
#Iterate through array from current index to find valid next odd jump
for index in range(current_index + 1, len(array)):
if array[index] >= array[current_index]:
if array[index] < min_value:
min_value = array[index]
next_index = index
return next_index
def find_next_even_jump(array, current_index):
next_index = -1
max_value = float('-inf')
#Iterate through array from current index to find valid next even jump
for index in range(current_index + 1, len(array)):
if array[index] <= array[current_index]:
if array[index] > max_value:
max_value = array[index]
next_index = index
return next_index
The key to solving this efficiently is to figure out for each position whether you can reach the end using only odd and even jumps. Instead of exploring every possible jump sequence, we pre-calculate reachability from each spot using a clever trick involving sorted positions.
Here's how the algorithm would work step-by-step:
def odd_even_jump(array) -> int:
array_length = len(array)
odd_jump_reachable = [False] * array_length
even_jump_reachable = [False] * array_length
odd_jump_reachable[array_length - 1] = True
even_jump_reachable[array_length - 1] = True
def find_next_jump(is_odd):
sorted_indices = sorted(range(array_length), key=lambda i: (array[i], -i if is_odd else i))
next_jump = [0] * array_length
stack = []
for index in sorted_indices:
while stack and index > stack[-1]:
next_jump[stack.pop()] = index
stack.append(index)
return next_jump
odd_jumps = find_next_jump(True)
even_jumps = find_next_jump(False)
# Work backwards to determine reachability
for i in range(array_length - 2, -1, -1):
# If an odd jump is possible, check reachability from there
if odd_jumps[i] != 0:
odd_jump_reachable[i] = even_jump_reachable[odd_jumps[i]]
# If an even jump is possible, check reachability from there
if even_jumps[i] != 0:
even_jump_reachable[i] = odd_jump_reachable[even_jumps[i]]
# Count starting positions that can reach the end via an odd jump
reachable_count = sum(odd_jump_reachable)
return reachable_count
Case | How to Handle |
---|---|
Empty input array | Return 0 as there are no jumps possible, indicating no starting index leads to the end. |
Single element array | Return 1, as the single element is considered a 'good' starting index. |
Array with all identical values | The next higher and next lower values will all point to the same index if one exists, potentially causing repeated jumps to the same location. |
Array sorted in ascending order | The odd jumps will always go to the next element, and the even jumps may never find a suitable smaller value to jump to. |
Array sorted in descending order | The even jumps will always go to the next element, and the odd jumps may never find a suitable larger value to jump to. |
Large array size (performance) | Use efficient data structures and algorithms (e.g., TreeMap, dynamic programming) to avoid exceeding time limit. |
Integer overflow when calculating indices or distances | Ensure calculations do not overflow by using appropriate data types or modulo operations where relevant. |
No possible path to the end of the array | The algorithm should correctly identify that no index can reach the end and return the correct number of 'good' indices. |