1. 跳跃游戏 Jump Game I
给定一个非负整数数组 nums
,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示:
1 <= nums.length <= 3 * 10^4
0 <= nums[i] <= 10^5
代码1: 贪心算法
class Solution: def canJump(self, nums): n = len(nums) max_pos = 0 for i in range(n): if i > max_pos: return False max_pos = max(max_pos, i+nums[i]) return True # %% s = Solution() print(s.canJump(nums = [2,3,1,1,4])) print(s.canJump(nums = [3,2,1,0,4]))
代码2:回溯算法
class Solution: def canJump(self,nums): def backtrack(pos): if pos == len(nums) - 1: return True furthestJump = min(pos + nums[pos], len(nums) - 1) for nextPos in range(furthestJump, pos, -1): if backtrack(nextPos): return True return False return backtrack(0) # %% s = Solution() print(s.canJump(nums = [2,3,1,1,4])) print(s.canJump(nums = [3,2,1,0,4]))
代码3: 反向贪心算法
class Solution: def canJump(self, nums): n = len(nums) last_pos = n - 1 for i in range(n - 2, -1, -1): if i + nums[i] >= last_pos: last_pos = i return last_pos == 0 # %% s = Solution() print(s.canJump(nums = [2,3,1,1,4])) print(s.canJump(nums = [3,2,1,0,4]))
代码4: 动态规划
class Solution: def canJump(self, nums): n = len(nums) dp = [False] * n dp[0] = True for i in range(1, n): for j in range(i): if dp[j] and j + nums[j] >= i: dp[i] = True break return dp[n-1] # %% s = Solution() print(s.canJump(nums = [2,3,1,1,4])) print(s.canJump(nums = [3,2,1,0,4]))
输出:
True
False
2. 跳跃游戏 Jump Game II
给你一个非负整数数组 nums ,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
代码1: 贪心算法
class Solution: def jump(self, nums): if len(nums) <= 1: return 0 end = 0 + nums[0] start = 0 step = 1 maxDis = 0 + nums[0] while end < len(nums) - 1: for i in range(start + 1, end + 1): maxDis = max(maxDis, nums[i] + i) start = end end = maxDis step += 1 return step # %% s = Solution() print(s.jump(nums = [2,3,1,1,4])) print(s.jump(nums = [2,3,0,1,4]))
代码2: 贪心算法
class Solution: def jump(self, nums): end, max_pos, steps = 0, 0, 0 for i in range(len(nums) - 1): max_pos = max(max_pos, i + nums[i]) if i == end: end = max_pos steps += 1 return steps # %% s = Solution() print(s.jump(nums = [2,3,1,1,4])) print(s.jump(nums = [2,3,0,1,4]))
代码3: 动态规划
class Solution: def jump(self,nums): n = len(nums) dp = [0] * n for i in range(1, n): dp[i] = float('inf') for j in range(i): if j + nums[j] >= i: dp[i] = min(dp[i], dp[j] + 1) return dp[n-1] # %% s = Solution() print(s.jump(nums = [2,3,1,1,4])) print(s.jump(nums = [2,3,0,1,4]))
输出:
2
2
3. 跳跃游戏 Jump Game III
这里有一个非负整数数组 arr,你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i + arr[i] 或者 i - arr[i]。
请你判断自己是否能够跳到对应元素值为 0 的 任一 下标处。
注意,不管是什么情况下,你都无法跳到数组之外。
示例 1:
输入:arr = [4,2,3,0,3,1,2], start = 5
输出:true
解释:
到达值为 0 的下标 3 有以下可能方案:
下标 5 -> 下标 4 -> 下标 1 -> 下标 3
下标 5 -> 下标 6 -> 下标 4 -> 下标 1 -> 下标 3
示例 2:
输入:arr = [4,2,3,0,3,1,2], start = 0
输出:true
解释:
到达值为 0 的下标 3 有以下可能方案:
下标 0 -> 下标 4 -> 下标 1 -> 下标 3
示例 3:
输入:arr = [3,0,2,1,2], start = 2
输出:false
解释:无法到达值为 0 的下标 1 处。
提示:
1 <= arr.length <= 5 * 10^4
0 <= arr[i] < arr.length
0 <= start < arr.length
代码: dfs\bfs
class Solution: def canReach_dfs(self, arr, start): visited = set() # 存储已经访问过的节点 def dfs(index): # 判断是否到达了值为 0 的位置 if arr[index] == 0: return True # 标记当前节点为已访问 visited.add(index) # 向左侧跳跃 if index - arr[index] >= 0 and index - arr[index] not in visited: if dfs(index - arr[index]): return True # 向右侧跳跃 if index + arr[index] < len(arr) and index + arr[index] not in visited: if dfs(index + arr[index]): return True # 无法到达值为 0 的位置 return False return dfs(start) def canReach_bfs(self, arr, start): from collections import deque queue = deque([start]) visited = set([start]) while queue: index = queue.popleft() # 判断是否到达了值为 0 的位置 if arr[index] == 0: return True # 向左侧跳跃 if index - arr[index] >= 0 and index - arr[index] not in visited: queue.append(index - arr[index]) visited.add(index - arr[index]) # 向右侧跳跃 if index + arr[index] < len(arr) and index + arr[index] not in visited: queue.append(index + arr[index]) visited.add(index + arr[index]) # 无法到达值为 0 的位置 return False # %% s = Solution() print(s.canReach_dfs(arr = [4,2,3,0,3,1,2], start = 5)) print(s.canReach_bfs(arr = [4,2,3,0,3,1,2], start = 5)) print(s.canReach_dfs(arr = [4,2,3,0,3,1,2], start = 0)) print(s.canReach_bfs(arr = [4,2,3,0,3,1,2], start = 0)) print(s.canReach_dfs(arr = [3,0,2,1,2], start = 2)) print(s.canReach_bfs(arr = [3,0,2,1,2], start = 2))
输出:
True
True
True
True
False
False
4. 跳跃游戏 Jump Game IV
给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。
每一步,你可以从下标 i 跳到下标 i + 1 、i - 1 或者 j :
i + 1 需满足:i + 1 < arr.length
i - 1 需满足:i - 1 >= 0
j 需满足:arr[i] == arr[j] 且 i != j
请你返回到达数组最后一个元素的下标处所需的 最少操作次数 。
注意:任何时候你都不能跳到数组外面。
示例 1:
输入:arr = [100,-23,-23,404,100,23,23,23,3,404]
输出:3
解释:那你需要跳跃 3 次,下标依次为 0 --> 4 --> 3 --> 9 。下标 9 为数组的最后一个元素的下标。
示例 2:
输入:arr = [7]
输出:0
解释:一开始就在最后一个元素处,所以你不需要跳跃。
示例 3:
输入:arr = [7,6,9,6,9,6,9,7]
输出:1
解释:你可以直接从下标 0 处跳到下标 7 处,也就是数组的最后一个元素处。
提示:
1 <= arr.length <= 5 * 10^4
-10^8 <= arr[i] <= 10^8
代码1: bfs
from collections import deque class Solution: def minJumps(self, arr): n = len(arr) if n == 1: return 0 # 将相同值的位置加入同一个集合中 value2index = {} for i, value in enumerate(arr): if value not in value2index: value2index[value] = set() value2index[value].add(i) # BFS 开始前的初始化 queue = deque([(0, 0)]) # 存储节点的队列,第一项为节点编号,第二项为到达该节点的最少操作数 visited = set() # 存储已经访问过的节点 visited.add(0) # BFS 遍历 while queue: index, step = queue.popleft() if index == n - 1: return step # 向左侧跳跃 if index - 1 >= 0 and index - 1 not in visited: queue.append((index - 1, step + 1)) visited.add(index - 1) # 向右侧跳跃 if index + 1 < n and index + 1 not in visited: queue.append((index + 1, step + 1)) visited.add(index + 1) # 跳到同值的位置 if arr[index] in value2index: for j in value2index[arr[index]]: if j not in visited: queue.append((j, step + 1)) visited.add(j) del value2index[arr[index]] # 避免重复访问 return -1 # 无法到达终点 # %% s = Solution() print(s.minJumps(arr = [100,-23,-23,404,100,23,23,23,3,404])) print(s.minJumps(arr = [7])) print(s.minJumps(arr = [7,6,9,6,9,6,9,7]))
代码2: bfs + 贪心算法
from collections import deque class Solution: def minJumps(self, arr): n = len(arr) if n == 1: return 0 # 构建同值位置哈希表 value2index = {} for i, value in enumerate(arr): if value not in value2index: value2index[value] = [] value2index[value].append(i) # BFS 开始前的初始化 queue = deque([0]) visited = set([0]) step = 0 # BFS 遍历 while queue: size = len(queue) for _ in range(size): index = queue.popleft() # 判断是否到达终点 if index == n - 1: return step # 跳到同值位置 if arr[index] in value2index: for j in value2index[arr[index]]: if j != index and j not in visited: queue.append(j) visited.add(j) del value2index[arr[index]] # 向左侧跳跃 if index - 1 >= 0 and index - 1 not in visited: queue.append(index - 1) visited.add(index - 1) # 向右侧跳跃 if index + 1 < n and index + 1 not in visited: queue.append(index + 1) visited.add(index + 1) step += 1 return -1 # 无法到达终点 # %% s = Solution() print(s.minJumps(arr = [100,-23,-23,404,100,23,23,23,3,404])) print(s.minJumps(arr = [7])) print(s.minJumps(arr = [7,6,9,6,9,6,9,7]))
输出:
3
0
1