Post

LC 55 - Jump Game

LC 55 - Jump Game

Question

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:

1
2
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:

1
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

Question here and solution here

Solution

concept

memoization

Use DFS to go through each possible path and cache

bottom up dp

we iterate from the back, and as long as the cells can reach the end (or a pre-calculated cells that can reach the end).

greedy

This solution is to move the goal post (from the end) towards the left. We iterate from the back and if the i + nums[i] >= goal it means that this cell can reach the goal and hence we can move the goal post to i. Subsequent cells as long as they can reach the goal it is consider True.

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
class Solution:
	"""
	brute force DFS
	"""
    def canJump(self, nums: List[int]) -> bool:
        def dfs(i):
            if i == len(nums) - 1:
                return True
	        if nums[i] == 0:
				return False
                
            end = min(len(nums) - 1, i + nums[i])
            for j in range(i + 1, end + 1): # range func does not include end
                if dfs(j):
                    return True
            return False

        return dfs(0)
        
class Solution:
	"""
	dp: top down (memoization)
	TLE
	"""
    def canJump(self, nums: List[int]) -> bool:
        memo = {}

        def dfs(i):
            if i in memo:
                return memo[i]
            if i == len(nums) - 1:
                return True
            if nums[i] == 0:
                return False

            end = min(len(nums) - 1, i + nums[i])
            for j in range(i + 1, end + 1):
                if dfs(j):
                    memo[i] = True
                    return True
            memo[i] = False
            return False

        return dfs(0)
        
class Solution:
	"""
	another top down (memoization)
	similar to above
	TLE
	"""
    def canJump(self, nums: List[int]) -> bool:
        cache = {}
        def dfs(i):
            if i in cache:
                return cache[i]
            if i == len(nums) - 1:
                return True
            if nums[i] == 0:
                return False
            if i >= len(nums):
                return False
            
            for j in range(1, nums[i] + 1):
                if dfs(i + j):
                    cache[i] = True
                    return cache[i]
            cache[i] = False
            return cache[i]

        return dfs(0)
        
class Solution:
	"""
	dp: bottom up
	"""
    def canJump(self, nums: List[int]) -> bool:
        dp = [False]*len(nums)
        dp[-1] = True

        for i in range(len(nums)-2, -1, -1):
            end = min(len(nums) - 1, i + nums[i])
            for j in range(i + 1, end + 1):
                if dp[j]:
                    dp[i] = True
                    break

        return dp[0]
        
class Solution:
	"""
	greedy
	"""
    def canJump(self, nums: List[int]) -> bool:
        goal = len(nums) - 1

        for i in range(len(nums)-1, -1, -1):
            if nums[i] + i >= goal:
                goal = i

        return True if goal == 0 else False

Complexity

time: $O(n^2)$ if DP, $O(n)$ if greedy
space: $O(n)$

This post is licensed under CC BY 4.0 by the author.