Reach zero
Problem Statement
You are given an array of integers of size and a starting index. Your task is to determine whether or not there the array contains a 0 that is “reachable” from the starting index. The array is not guarenteed to contain the integer 0.
An element can reach an element if is exactly elements to the left or the right of element . For example, in an array [2, 4, 1, 3, 6, 9]
, the element 1 can reach both 4 and 3 because they are each exactly one element away. If the element’s reach extends beyond the indices of the array, its reach does not wrap around. For example, the element 3 cannot reach any elements to its right.
Design an algorithm that will return a boolean indicating whether or not a 0 is reachable in the array.
Test Cases
Test Case 1
Input: [3, 2, 4, 5, 0, 1, 2, 9, 3]
, starting index: 0
Output: True
Test Case 2
Input: [2, 3, 5, 3, 8, 3, 0, 3, 5, 1, 3]
, starting index: 2
Output: False
Test Case 3
Input: [2, 3, 1, 4, 1, 4]
, starting index: 1
Output: False
Hints
Click Here
What happens on an input array of [1,1]
? How can you ensure your algorithm ends?
Follow up question:
What is the runtime of this algorithm?
Click Below to see the Solution
Algorithm
The idea is to use recursion to determine whether each decision (traversing left or right) ever reaches 0. If at any point we have traversed all of the elements or are checking the same element twice, then we know the path we have taken so far is invalid.
Code
def _reachZero(arr, start):
# the visited array keeps track of which indices we've visited so we don't recheck
# indices and get into an infinite loop
visited = [0] * len(arr)
return reachZeroHelper(arr, start, visited)
def _reachZeroHelper(arr, start, visited):
if (sum(visited) == len(arr)) or (start < 0) or (start > len(arr) - 1):
return false
if (arr[start] == 0):
return true
else:
visited[start] = 1
left = reachZeroHelper(arr, start - arr[start], visited)
right = reachZeroHelper(arr, start + arr[start], visited)
return (left or right)
Walkthrough
With Input: [3, 2, 4, 5, 0, 1, 2, 9, 3]
and starting index: 0
:
-
Since the starting vertex is
0
,left = reachZeroHelper(arr, 0 - 3, visited)
andright = reachZeroHelper(arr, 0 + 3, visited)
. -
Therefore
left = false
, since . -
After its recursive call,
right = reachZeroHelper(arr, 3 - 5, visited) || reachZeroHelper(arr, 3 + 5, visited)
. -
reachZeroHelper(arr, 3 - 5, visited) = false
, since , soright = reachZeroHelper(arr, 8, visited)
-
After another recursive call,
right = reachZeroHelper(arr, 8 - 3, visited) || reachZeroHelper(arr, 8 + 3, visited)
. -
reachZeroHelper(arr, 8 + 3, visited) = false
, since11 > 9 - 1
, soright = reachZeroHelper(arr, 8 - 3, visited)
. -
After another recursive call,
right = reachZeroHelper(arr, 5 - 1, visited) || reachZeroHelper(arr, 5 + 1, visited)
. -
Since arr[4] == 0, we return true.
Runtime Analysis
Since we only need to check each index at most once, the algorithm runs in time. If your algorithm has a runtime any greater than linear, then you are re-checking indices and can get into an infinite loop.