diff --git a/DIRECTORY.md b/DIRECTORY.md index 49dafb19..70c4d43f 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -85,6 +85,8 @@ * Greedy * Gas Stations * [Test Gas Stations](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/greedy/gas_stations/test_gas_stations.py) + * Jump Game + * [Test Jump Game](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/greedy/jump_game/test_jump_game.py) * Majority Element * [Test Majority Element](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/greedy/majority_element/test_majority_element.py) * Min Arrows @@ -497,8 +499,6 @@ * [Test H Index](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/arrays/h_index/test_h_index.py) * Increasing Triplet Subsequence * [Test Increasing Triplet](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/arrays/increasing_triplet_subsequence/test_increasing_triplet.py) - * Jump Game - * [Test Jump Game](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/arrays/jump_game/test_jump_game.py) * Kid With Greatest No Of Candies * [Test Kids With Greatest Candies](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/arrays/kid_with_greatest_no_of_candies/test_kids_with_greatest_candies.py) * Longest Increasing Subsequence diff --git a/algorithms/greedy/jump_game/README.md b/algorithms/greedy/jump_game/README.md new file mode 100644 index 00000000..f796ebf7 --- /dev/null +++ b/algorithms/greedy/jump_game/README.md @@ -0,0 +1,205 @@ +# Jump Game + +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. + +```text +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. +``` + +```text +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. +``` + +## Solutions + +1. [Naive Approach](#naive-approach) +1. [Optimized Approach using Greedy Pattern](#optimized-approach-using-greedy-pattern) + +### Naive Approach + +The naive approach explores all possible jump sequences from the starting position to the end of the array. It begins +at the first index and attempts to jump to every reachable position from the current index, recursively repeating this +process for each new position. If a path successfully reaches the last index, the algorithm returns success. If it +reaches a position without further moves, it backtracks to try a different path. + +While this method guarantees that all possible paths are considered, it is highly inefficient, as it explores many +redundant or dead-end routes. The time complexity of this backtracking approach is exponential, making it impractical +for large inputs. + +### Optimized Approach using Greedy Pattern + +An optimized way to solve this problem is using a greedy approach that works in reverse. Instead of trying every +possible forward jump, we flip the logic: start from the end and ask, “Can we reach this position from any earlier index?” + +We begin with the last index as our initial target—the position we want to reach. Then, we move backward through the +array, checking whether the current index has a jump value large enough to reach or go beyond the current target. If it +can, we update the target to that index. This means that reaching this earlier position would eventually allow us to +reach the end. By continuously updating the target, we’re effectively identifying the leftmost position from which the +end is reachable. + +This process continues until we reach the first index or determine that no earlier index can reach the current target. +If we finish with the target at index 0, it means the start of the array can lead to the end, so we return TRUE. If the +target remains beyond index 0, then no path exists from the start to the end, and we return FALSE. + +![Solution 1](./images/solutions/jump_game_1_solution_1.png) +![Solution 2](./images/solutions/jump_game_1_solution_2.png) +![Solution 3](./images/solutions/jump_game_1_solution_3.png) +![Solution 4](./images/solutions/jump_game_1_solution_4.png) +![Solution 5](./images/solutions/jump_game_1_solution_5.png) +![Solution 6](./images/solutions/jump_game_1_solution_6.png) +![Solution 7](./images/solutions/jump_game_1_solution_7.png) +![Solution 8](./images/solutions/jump_game_1_solution_8.png) +![Solution 9](./images/solutions/jump_game_1_solution_9.png) +![Solution 10](./images/solutions/jump_game_1_solution_10.png) +![Solution 11](./images/solutions/jump_game_1_solution_11.png) + +#### Algorithm + +1. We begin by setting the last index of the array as our initial target using the variable target = len(nums) - 1. This + target represents the position we are trying to reach, starting from the end and working backward. By initializing the + target this way, we define our goal: to find out if there is any index i from which the target is reachable based on the + value at that position, nums[i]. This also sets the stage for updating the target if such an index is found. + +2. Next, we loop backward through the array using for i in range(len(nums) - 2, -1, -1). Here, i represents the current + index we are analyzing. At each index i, the value nums[i] tells us how far we can jump forward from that position. + By checking whether i + nums[i] >= target, we determine whether it can reach the current target from index i. This + step allows us to use the jump range at each position to decide if it can potentially lead us to the end. + +3. If the condition i + nums[i] >= target is TRUE, the current index i can jump far enough to reach the current target. + In that case, we update target = i, effectively saying, “Now we just need to reach index i instead.” If the condition + fails, we move back in the array one step further and try again with the previous index. + We repeat this process until we either: + - Successfully moving the target back to index 0 means the start of the array can reach the end. In this case, we + return TRUE. + - Or reach the start without ever being able to update the target to 0, which means there is no valid path. In this + case, we return FALSE. + +#### Solution Summary + +1. Set the last index of the array as the target index. +2. Traverse the array backward and verify if we can reach the target index from any of the previous indexes. + - If we can reach it, we update the target index with the index that allows us to jump to the target index. + - We repeat this process until we’ve traversed the entire array. +3. Return TRUE if, through this process, we can reach the first index of the array. Otherwise, return FALSE. + +#### Time Complexity + +The time complexity of the above solution is O(n), since we traverse the array only once, where n is the number of +elements in the array. + +#### Space Complexity + +The space complexity of the above solution is O(1), because we do not use any extra space. + + +--- + +# Jump Game II + +You are given a 0-indexed array of integers nums of length n. You are initially positioned at nums[0]. + +Each element nums[i] represents the maximum length of a forward jump from index i. In other words, if you are at +nums[i], you can jump to any nums[i + j] where: + +0 <= j <= nums[i] and +i + j < n +Return the minimum number of jumps to reach nums[n - 1]. The test cases are generated such that you can reach +nums[n - 1]. + +```text +Example 1: + +Input: nums = [2,3,1,1,4] +Output: 2 +Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to +the last index. +``` + +```text +Example 2: + +Input: nums = [2,3,0,1,4] +Output: 2 +``` + +![Example 1](./images/examples/jump_game_2_example_1.png) +![Example 2](./images/examples/jump_game_2_example_2.png) +![Example 3](./images/examples/jump_game_2_example_3.png) +![Example 4](./images/examples/jump_game_2_example_4.png) +![Example 5](./images/examples/jump_game_2_example_5.png) +![Example 6](./images/examples/jump_game_2_example_6.png) + +## Solution + +We’ll solve this problem using a greedy approach. At each step, we choose the jump that allows us to reach the farthest +point. The objective is to minimize the number of jumps required to reach the end of the array. This strategy is +considered greedy because it selects the best possible move at each step without considering the impact on future jumps. +By always jumping as far as possible, we cover more distance and use fewer jumps to reach the end. + +To find the minimum number of jumps needed to reach the end of the array, keep track of how far you can go with the +current number of jumps. As you progress through the array, update this maximum reach based on your current position. +When you reach the limit of your current jump range, increase your jump count and adjust the range to the farthest +position you can reach with the next jump. Continue this process until you reach or exceed the end of the array. + +The steps of the algorithm are given below: + +1. Initialize three variables, all set to 0. + - `jumps`: This variable tracks the minimum number of jumps required to reach the end of the array and will be + returned as the final output. + - `current_jump_boundary`: This represents the maximum index we can reach with the current number of jumps. It acts + as the boundary of how far we can go before making another jump. + - `farthest_jump_index`: This tracks the farthest index we can reach from the current position by considering all + possible jumps within the current jump’s range. + +2. Iterate through the nums array and perform the following steps: + - Update `farthest_jump_index`: For each index i, calculate i + nums[i], which represents the farthest index we can + reach from i. Update farthest_jump_index to be the maximum of its current value and i + nums[i]. + - Check if a new jump is needed: If i equals current_jump_boundary, it means we’ve reached the limit of the current + jump. Increment jumps by 1, and update current_jump_boundary to farthest_jump_index to set up for the next jump. + +3. After iterating through the array, jumps will contain the minimum number of jumps needed to reach the end. Return + this value as the output. + +Let’s look at the following illustration to get a better understanding of the solution: + +![Solution 1](./images/solutions/jump_game_2_solution_1.png) +![Solution 2](./images/solutions/jump_game_2_solution_2.png) +![Solution 3](./images/solutions/jump_game_2_solution_3.png) +![Solution 4](./images/solutions/jump_game_2_solution_4.png) +![Solution 5](./images/solutions/jump_game_2_solution_5.png) +![Solution 6](./images/solutions/jump_game_2_solution_6.png) +![Solution 7](./images/solutions/jump_game_2_solution_7.png) +![Solution 8](./images/solutions/jump_game_2_solution_8.png) +![Solution 9](./images/solutions/jump_game_2_solution_9.png) +![Solution 10](./images/solutions/jump_game_2_solution_10.png) +![Solution 11](./images/solutions/jump_game_2_solution_11.png) +![Solution 12](./images/solutions/jump_game_2_solution_12.png) +![Solution 13](./images/solutions/jump_game_2_solution_13.png) + +### Time Complexity + +The time complexity of the above solution is O(n), where n is the length of nums because we are iterating the array once. + +### Space Complexity + +The space complexity of the above solution is O(1), because we are not using any extra space. + +--- + +# Topics + +- Array +- Dynamic Programming +- Greedy diff --git a/algorithms/greedy/jump_game/__init__.py b/algorithms/greedy/jump_game/__init__.py new file mode 100644 index 00000000..309e4e2d --- /dev/null +++ b/algorithms/greedy/jump_game/__init__.py @@ -0,0 +1,127 @@ +from typing import List + + +def can_jump(nums: List[int]) -> bool: + """ + This function checks if it is possible to reach the last index of the array from the first index. + Args: + nums(list): list of integers + Returns: + bool: True if can jump to the last index, False otherwise + """ + + current_position = nums[0] + + for idx in range(1, len(nums)): + if current_position == 0: + return False + + current_position -= 1 + + current_position = max(current_position, nums[idx]) + + return True + + +def can_jump_2(nums: List[int]) -> bool: + """ + This function checks if it is possible to reach the last index of the array from the first index. + + This variation starts checking from the last element in the input list and tracking back to check if it is possible + to reach the end. + + Args: + nums(list): list of integers + Returns: + bool: True if can jump to the last index, False otherwise + """ + target_num_index = len(nums) - 1 + + for idx in range(len(nums) - 2, -1, -1): + if target_num_index <= idx + nums[idx]: + target_num_index = idx + + if target_num_index == 0: + return True + return False + + +def jump(nums: List[int]) -> int: + """ + This function returns the minimum number of jumps needed to reach the last index of the array from the first index. + Args: + nums(list): list of integers + Returns: + int: minimum number of jumps needed to reach the last index + """ + size = len(nums) + # if start index == destination index == 0 + if size == 1: + return 0 + + # destination is last index + destination = size - 1 + + # record of current coverage, record of last jump index + current_coverage, last_jump_index = 0, 0 + + # min number of jumps + min_jumps = 0 + + # Greedy strategy: extend coverage as long as possible with lazy jump + for idx in range(size): + # extend coverage as far as possible + current_coverage = max(current_coverage, idx + nums[idx]) + + # forced to jump (by lazy jump) to extend coverage + if idx == last_jump_index: + # update last jump index + last_jump_index = current_coverage + + # update counter of jump by +1 + min_jumps += 1 + + # check if destination has been reached + if current_coverage >= destination: + return min_jumps + + return min_jumps + + +def jump_2(nums: List[int]) -> int: + """ + This function returns the minimum number of jumps needed to reach the last index of the array from the first index. + Args: + nums(list): list of integers + Returns: + int: minimum number of jumps needed to reach the last index + """ + # Store the length of the input array + size = len(nums) + + # if start index == destination index == 0 + if size == 1: + return 0 + + # Initialize the variables to track the number of jumps, + # the current jump's limit, and the farthest reachable index + min_jumps = 0 + current_jump_boundary = 0 + furthest_jump_index = 0 + + # Iterate through the array, stopping before the last element + for idx in range(size - 1): + # Update the farthest_jump_index to be the maximum of its current value + # and the index we can reach from the current position + furthest_jump_index = max(furthest_jump_index, idx + nums[idx]) + + # If we have reached the limit of the current jump + if idx == current_jump_boundary: + # update counter of jump by +1 + min_jumps += 1 + + # Update the current_jump_boundary to the farthest we can reach + current_jump_boundary = furthest_jump_index + + # Return the total number of jumps needed to reach the end of the array + return min_jumps diff --git a/algorithms/greedy/jump_game/images/examples/jump_game_2_example_1.png b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_1.png new file mode 100644 index 00000000..428e8d72 Binary files /dev/null and b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_1.png differ diff --git a/algorithms/greedy/jump_game/images/examples/jump_game_2_example_2.png b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_2.png new file mode 100644 index 00000000..84eb8168 Binary files /dev/null and b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_2.png differ diff --git a/algorithms/greedy/jump_game/images/examples/jump_game_2_example_3.png b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_3.png new file mode 100644 index 00000000..22531d02 Binary files /dev/null and b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_3.png differ diff --git a/algorithms/greedy/jump_game/images/examples/jump_game_2_example_4.png b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_4.png new file mode 100644 index 00000000..55fb6f5a Binary files /dev/null and b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_4.png differ diff --git a/algorithms/greedy/jump_game/images/examples/jump_game_2_example_5.png b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_5.png new file mode 100644 index 00000000..7c06c5be Binary files /dev/null and b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_5.png differ diff --git a/algorithms/greedy/jump_game/images/examples/jump_game_2_example_6.png b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_6.png new file mode 100644 index 00000000..f98fb736 Binary files /dev/null and b/algorithms/greedy/jump_game/images/examples/jump_game_2_example_6.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_1.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_1.png new file mode 100644 index 00000000..e70badf7 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_1.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_10.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_10.png new file mode 100644 index 00000000..9632e029 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_10.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_11.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_11.png new file mode 100644 index 00000000..d6c7e592 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_11.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_2.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_2.png new file mode 100644 index 00000000..cb11e004 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_2.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_3.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_3.png new file mode 100644 index 00000000..ee16b255 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_3.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_4.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_4.png new file mode 100644 index 00000000..95214bf6 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_4.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_5.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_5.png new file mode 100644 index 00000000..1ab34475 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_5.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_6.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_6.png new file mode 100644 index 00000000..310b0300 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_6.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_7.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_7.png new file mode 100644 index 00000000..eb6c4be8 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_7.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_8.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_8.png new file mode 100644 index 00000000..c86f6f63 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_8.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_9.png b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_9.png new file mode 100644 index 00000000..63d42c76 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_1_solution_9.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_1.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_1.png new file mode 100644 index 00000000..774c214f Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_1.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_10.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_10.png new file mode 100644 index 00000000..8853519f Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_10.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_11.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_11.png new file mode 100644 index 00000000..d52fcfb3 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_11.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_12.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_12.png new file mode 100644 index 00000000..7279e8df Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_12.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_13.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_13.png new file mode 100644 index 00000000..dc735f9c Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_13.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_2.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_2.png new file mode 100644 index 00000000..e6f674ab Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_2.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_3.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_3.png new file mode 100644 index 00000000..6a5b3c59 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_3.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_4.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_4.png new file mode 100644 index 00000000..179b7916 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_4.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_5.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_5.png new file mode 100644 index 00000000..745a1abb Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_5.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_6.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_6.png new file mode 100644 index 00000000..2a2a3188 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_6.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_7.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_7.png new file mode 100644 index 00000000..067ee828 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_7.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_8.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_8.png new file mode 100644 index 00000000..c8a14279 Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_8.png differ diff --git a/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_9.png b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_9.png new file mode 100644 index 00000000..640e837d Binary files /dev/null and b/algorithms/greedy/jump_game/images/solutions/jump_game_2_solution_9.png differ diff --git a/algorithms/greedy/jump_game/test_jump_game.py b/algorithms/greedy/jump_game/test_jump_game.py new file mode 100644 index 00000000..890ba93f --- /dev/null +++ b/algorithms/greedy/jump_game/test_jump_game.py @@ -0,0 +1,53 @@ +import unittest +from typing import List +from parameterized import parameterized +from algorithms.greedy.jump_game import can_jump, jump, can_jump_2, jump_2 + +CAN_JUMP_TEST_DATA = [ + ([2, 3, 1, 1, 4], True), + ([3, 2, 1, 0, 4], False), + ([2, 3, 0, 1, 4], True), + ([0], True), + ([1, 0, 1, 0], False), + ([4, 0, 0, 0, 1], True), + ([2, 3, 1, 1, 9], True), + ([4, 0, 0, 0, 4], True), + ([1], True), +] + + +class CanJumpTestCase(unittest.TestCase): + @parameterized.expand(CAN_JUMP_TEST_DATA) + def test_can_jump(self, nums: List[int], expected: bool): + actual = can_jump(nums) + self.assertEqual(expected, actual) + + @parameterized.expand(CAN_JUMP_TEST_DATA) + def test_can_jump_2(self, nums: List[int], expected: bool): + actual = can_jump_2(nums) + self.assertEqual(expected, actual) + + +JUMP_GAME_TEST_DATA = [ + ([2, 3, 1, 1, 4], 2), + ([2, 3, 1, 1, 9], 2), + ([3, 2, 1, 1, 4], 2), + ([4, 0, 0, 0, 4], 1), + ([1], 0), +] + + +class JumpTestCase(unittest.TestCase): + @parameterized.expand(JUMP_GAME_TEST_DATA) + def test_jump_game(self, nums: List[int], expected: int): + actual = jump(nums) + self.assertEqual(expected, actual) + + @parameterized.expand(JUMP_GAME_TEST_DATA) + def test_jump_game_2(self, nums: List[int], expected: int): + actual = jump_2(nums) + self.assertEqual(expected, actual) + + +if __name__ == "__main__": + unittest.main() diff --git a/puzzles/arrays/jump_game/README.md b/puzzles/arrays/jump_game/README.md deleted file mode 100644 index 80ff9e37..00000000 --- a/puzzles/arrays/jump_game/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# Jump Game - -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. - -```text -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. -``` - -```text -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. -``` - ---- - -## Jump Game II - -You are given a 0-indexed array of integers nums of length n. You are initially positioned at nums[0]. - -Each element nums[i] represents the maximum length of a forward jump from index i. In other words, if you are at -nums[i], you can jump to any nums[i + j] where: - -0 <= j <= nums[i] and -i + j < n -Return the minimum number of jumps to reach nums[n - 1]. The test cases are generated such that you can reach -nums[n - 1]. - -```text -Example 1: - -Input: nums = [2,3,1,1,4] -Output: 2 -Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to -the last index. -``` - -```text -Example 2: - -Input: nums = [2,3,0,1,4] -Output: 2 -``` - ---- - -## Topics - -- Array -- Dynamic Programming -- Greedy diff --git a/puzzles/arrays/jump_game/__init__.py b/puzzles/arrays/jump_game/__init__.py deleted file mode 100644 index c525fdb4..00000000 --- a/puzzles/arrays/jump_game/__init__.py +++ /dev/null @@ -1,50 +0,0 @@ -from typing import List - - -def can_jump(nums: List[int]) -> bool: - current_position = nums[0] - - for idx in range(1, len(nums)): - if current_position == 0: - return False - - current_position -= 1 - - current_position = max(current_position, nums[idx]) - - return True - - -def jump(nums: List[int]) -> int: - size = len(nums) - # destination is last index - destination = size - 1 - - # record of current coverage, record of last jump index - current_coverage, last_jump_index = 0, 0 - - # min number of jumps - min_jumps = 0 - - # if start index == destination index == 0 - if size == 1: - return 0 - - # Greedy strategy: extend coverage as long as possible with lazy jump - for idx in range(size): - # extend coverage as far as possible - current_coverage = max(current_coverage, idx + nums[idx]) - - # forced to jump (by lazy jump) to extend coverage - if idx == last_jump_index: - # update last jump index - last_jump_index = current_coverage - - # update counter of jump by +1 - min_jumps += 1 - - # check if destination has been reached - if current_coverage >= destination: - return min_jumps - - return min_jumps diff --git a/puzzles/arrays/jump_game/test_jump_game.py b/puzzles/arrays/jump_game/test_jump_game.py deleted file mode 100644 index 36c95b74..00000000 --- a/puzzles/arrays/jump_game/test_jump_game.py +++ /dev/null @@ -1,43 +0,0 @@ -import unittest - -from . import can_jump, jump - - -class CanJumpTestCase(unittest.TestCase): - def test_1(self): - """nums = [2,3,1,1,4] should return true""" - nums = [2, 3, 1, 1, 4] - actual = can_jump(nums) - self.assertTrue(actual) - - def test_2(self): - """nums = [3,2,1,0,4] should return false""" - nums = [3, 2, 1, 0, 4] - actual = can_jump(nums) - self.assertFalse(actual) - - def test_3(self): - """nums = [2, 3, 0, 1, 4] should return true""" - nums = [2, 3, 0, 1, 4] - actual = can_jump(nums) - self.assertTrue(actual) - - -class JumpTestCase(unittest.TestCase): - def test_1(self): - """nums = [2,3,1,1,4] should return 2""" - nums = [2, 3, 1, 1, 4] - actual = jump(nums) - expected = 2 - self.assertEqual(expected, actual) - - def test_3(self): - """nums = [2, 3, 0, 1, 4] should return 2""" - nums = [2, 3, 0, 1, 4] - actual = jump(nums) - expected = 2 - self.assertEqual(expected, actual) - - -if __name__ == "__main__": - unittest.main()