3 minute read

Problem Statement

You are given an integer array nums. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position.

Return true if you can reach the last index, or false otherwise.

 

Example 1:

Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:

Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
 

Constraints:

1 <= nums.length <= 104
0 <= nums[i] <= 105

Brute Force - TLE

Intuition

I initially recognize that this problem involves determining whether it’s possible to reach the last index of an array by jumping through its elements. My intuition tells me that a depth-first search (DFS) approach could be a way to solve this problem.

Approach

The approach here is to use DFS with memoization to avoid redundant calculations. The function canJump takes the input array nums and initializes a memoization dictionary. The recursive function dfs is defined to explore possible jumps from the current index. If the last index is reached or surpassed, the function returns True. It iterates over possible steps and recursively calls itself to check if it’s possible to reach the end from the next index.

Complexity

  • Time complexity: O(n^2). In the worst case, the algorithm might explore all possible jumps for each index, resulting in a quadratic time complexity.

  • Space complexity: O(n). The space complexity is determined by the memoization dictionary, which stores results for each index to avoid redundant calculations.

Code

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        N = len(nums)
        memo = {}
        def dfs(index):
            if index >= N - 1:
                return True

            if index in memo:
                return memo[index]

            steps = nums[index]
            result = False
            for step in range(steps, 0, -1):
                if dfs(index + step):
                    result = True
                    break
            
            memo[index] = result
            return result

        return dfs(0)

Other Approach - TLE

In this approach, I attempted to create a dp array to simulate the jump the process. However, it doesn’t pass the Leet Code Judge due to runtime is too long.

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        N = len(nums)
        dp = [False] * N
        dp[0] = True
        for i in range(N):
            steps = nums[i]
            if dp[i]:
                for j in range(steps, 0, -1):
                    if i + j < N:
                        dp[i + j] = True
        
        return dp[-1]

Time Complexity: O(n^2) Space Complexity: O(n^2)

BFS - Memory Limit Exceeded

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        N = len(nums)
        queue = deque()
        queue.append(0)
        while queue:
            index = queue.popleft()
            if index == N - 1:
                return True
            steps = nums[index]
            for i in range(1, steps + 1):
                queue.append(index + i)
        return False

Editorial Solution

The Most Optimize Solution - Greedy

The idea is to move backward to check for the viable paths.

The approach involves a backward traversal of the array. The variable last_pos represents the last known position that is guaranteed to be reachable. Starting from the last index and moving towards the beginning, the algorithm checks if the current index, along with the number of steps it can take, reaches or surpasses the last_pos. If it does, update last_pos to the current index. After completing the traversal, check if the last_pos is at the beginning (index 0) of the array.

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        N = len(nums)
        last_pos = N - 1
        for i in range(N - 1, -1, -1):
            if i + nums[i] >= last_pos:
                last_pos = i
        return last_pos == 0

Time Complexity: O(n) Space Complexity: O(1)