跳跃游戏系列挑战:一步步征服编程难关
2024-01-10 00:38:47
前言
LeetCode Jump Game系列是算法竞赛中颇具挑战性的一组题目,考察选手对动态规划的掌握程度和优化算法效率的能力。本篇文章将带领您逐一攻破七道题目,提供Kotlin代码和详细的解题思路,帮助您全面提升编程技能。
1. 跳跃游戏 I
题目
给定一个非负整数数组,表示可以从当前位置向前跳跃的距离。判断是否能够从数组的第一个位置跳到最后一个位置。
解题思路:
采用贪心算法,从第一个位置开始,每次跳跃至最远可达位置。若存在无法到达的位置,则返回false。
fun canJump(nums: IntArray): Boolean {
var maxReach = 0
for (i in 0 until nums.lastIndex) {
if (i > maxReach) return false
maxReach = maxOf(maxReach, i + nums[i])
}
return maxReach >= nums.lastIndex
}
2. 跳跃游戏 II
题目:
与跳跃游戏 I 类似,但这次需要计算从第一个位置跳到最后一个位置的最少跳跃次数。
解题思路:
采用动态规划,以子问题(从不同位置跳到最后一个位置的最小跳跃次数)的结果来构建整体解决方案。
fun jump(nums: IntArray): Int {
val n = nums.size
val dp = IntArray(n) { Int.MAX_VALUE }
dp[n - 1] = 0
for (i in n - 2 downTo 0) {
for (j in i + 1..minOf(n - 1, i + nums[i])) {
dp[i] = minOf(dp[i], dp[j] + 1)
}
}
return if (dp[0] == Int.MAX_VALUE) -1 else dp[0]
}
3. 跳跃游戏 III
题目:
给定一个非负整数数组,表示可以从当前位置向前跳跃的距离,以及一个整数k,判断是否能够从数组的第一个位置跳到最后一个位置,且最多跳跃k次。
解题思路:
采用回溯法,从第一个位置开始尝试跳跃,若成功到达最后一个位置或跳跃次数达到k,则返回true。否则继续尝试下一个可跳跃位置。
fun canJump(nums: IntArray, k: Int): Boolean {
return canJumpFromPosition(nums, 0, k)
}
private fun canJumpFromPosition(nums: IntArray, position: Int, k: Int): Boolean {
if (position == nums.lastIndex) return true
if (position > nums.lastIndex || k <= 0) return false
for (i in 1..minOf(k, nums[position])) {
if (canJumpFromPosition(nums, position + i, k - i)) {
return true
}
}
return false
}
4. 跳跃游戏 IV
题目描述:
与跳跃游戏 III 类似,但这次需要计算从第一个位置跳到最后一个位置的最少跳跃次数,且最多跳跃k次。
解题思路:
采用动态规划,以子问题(从不同位置跳到最后一个位置的最少跳跃次数)的结果来构建整体解决方案。
fun minJumps(nums: IntArray, k: Int): Int {
val n = nums.size
val dp = IntArray(n) { Int.MAX_VALUE }
dp[n - 1] = 0
for (i in n - 2 downTo 0) {
for (j in i + 1..minOf(n - 1, i + nums[i])) {
if (dp[j] != Int.MAX_VALUE) {
dp[i] = minOf(dp[i], dp[j] + 1)
}
}
if (i + k < n) {
dp[i] = minOf(dp[i], dp[i + k] + 1)
}
}
return if (dp[0] == Int.MAX_VALUE) -1 else dp[0]
}
5. 跳跃游戏 V
题目描述:
给定一个非负整数数组,表示可以从当前位置向前跳跃的距离。判断是否能够从数组的第一个位置跳到最后一个位置,且最多跳跃k次,且每个位置只能跳跃一次。
解题思路:
采用回溯法,从第一个位置开始尝试跳跃,若成功到达最后一个位置或跳跃次数达到k,则返回true。否则继续尝试下一个可跳跃位置。同时记录已经跳跃过的位置,避免重复跳跃。
fun canJump(nums: IntArray, k: Int): Boolean {
val visited = BooleanArray(nums.size)
return canJumpFromPosition(nums, 0, k, visited)
}
private fun canJumpFromPosition(nums: IntArray, position: Int, k: Int, visited: BooleanArray): Boolean {
if (position == nums.lastIndex) return true
if (position > nums.lastIndex || k <= 0) return false
if (visited[position]) return false
visited[position] = true
for (i in 1..minOf(k, nums[position])) {
if (canJumpFromPosition(nums, position + i, k - i, visited)) {
return true
}
}
return false
}
6. 跳跃游戏 VI
题目描述:
与跳跃游戏 V 类似,但这次需要计算从第一个位置跳到最后一个位置的最少跳跃次数,且最多跳跃k次,且每个位置只能跳跃一次。
解题思路:
采用动态规划,以子问题(从不同位置跳到最后一个位置的最少跳跃次数)的结果来构建整体解决方案。
fun minJumps(nums: IntArray, k: Int): Int {
val n = nums.size
val dp = IntArray(n) { Int.MAX_VALUE }
dp[n - 1] = 0
for (i in n - 2 downTo 0) {
for (j in i + 1..minOf(n - 1, i + nums[i])) {
if (dp[j] != Int.MAX_VALUE) {
dp[i] = minOf(dp[i], dp[j] + 1)
}
}
if (i + k < n) {
dp[i] = minOf(dp[i], dp[i + k] + 1)
}
}
return if (dp[0] == Int.MAX_VALUE) -1 else dp[0]
}
7. 跳跃游戏 VII
题目描述:
给定一个非负整数数组,表示可以从当前位置向前跳跃的距离。判断是否能够从数组的第一个位置跳到最后一个位置,且最多跳跃k次,且每个位置只能跳跃一次,且跳跃过程中不能跨越任何障碍。
解题思路:
采用回溯法,从第一个位置开始尝试跳跃,若成功到达最后一个位置或跳跃次数达到k,则返回true。否则继续尝试下一个可跳跃位置。同时记录已经跳跃过的位置,避免重复跳跃,并记录已经跨越过的障碍,避免跨越障碍。
fun canJump(nums: IntArray, k: Int): Boolean {
val visited = BooleanArray(nums.size)
val obstacles = BooleanArray(nums.size)
return canJumpFromPosition(nums, 0, k, visited, obstacles)
}
private fun canJumpFromPosition(nums: IntArray, position: Int, k: Int, visited: BooleanArray, obstacles: BooleanArray): Boolean {
if (position == nums.lastIndex) return true
if (position > nums.lastIndex || k <= 0) return false
if (visited[position]) return false
if (obstacles[position]) return false
visited[position] = true
for (i in 1..minOf(k, nums[position])) {
if (position + i