跳跃游戏——贪心

90 阅读2分钟

image.png

贪心代码1:

  1. 反向查找出发位置
  2. 遍历数组,找到第一个可以跳到目标位置的下标
  3. 因为我们要找最小下标,所以遍历查找的时候是正向遍历,而目标位置我们是从最终位置开始的,
  4. 也就是目标反向遍历,查找正向查找
func jump(nums []int) int {
    position := len(nums) - 1
    steps := 0
    for position > 0 {
        for i := 0; i < position; i++ {
            if i + nums[i] >= position {
                position = i
                steps++
                break
            }
        }
    }
    return steps
}

贪心代码2:

  1. 代码1简单易懂但最坏情况时间复杂度 N 平方
  2. 但其实我们正向查找,直接找可以到达最远下标,也就是遍历一次就好
  3. 如下代码
  4. end为当前可以跳的最远距离,mx为下一步可以跳到最远距离
  5. i == end , 并非是当前跳到了end,只是我们遍历到end时,我们的mx成功维护了下一步的最远距离,所以此时更新end以及ans
  6. 因为我们把第 0 步也ans++了所以我们最后一步不再加ans,
  7. 这样写的好处是,我们将最小的那个临界值一并考虑了,即数组里只有一个值,起点便是终点
func jump(nums []int) int {
    ans := 0
    end := 0
    mx := 0
    for i := 0; i < len(nums)-1; i++ {
        mx = max(mx, nums[i] + i) 
        if i == end {
            end = mx
            ans++
        }
    }
    return ans
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

代码3:

  1. 此代码也就是代码2的初始版本,
func jump(nums []int) int {
    n := len(nums)
    if n == 1 {
        // 若数组长度为1,不需要跳跃
        return 0
    }
    // 跳跃次数至少为1,第一次跳跃起始位置为0,最远可以跳到 0+nums[0]
    jumpNums, start, end, maxLen := 1, 1, nums[0], nums[0]
    // 在[start, end]范围内更新下一次跳跃能够到达的最远距离maxLen,直到抵达数组尾部
    for maxLen < n-1 {
        for i := start; i <= end; i++ {
            if i + nums[i] > maxLen {
                maxLen = i + nums[i]
            }
        }
        // 跳跃次数+1
        jumpNums++
        // 更新start和end
        start = end + 1
        end = maxLen
    }
    return jumpNums
}