当前位置: 首页 > news >正文

LeetCode 45.跳跃游戏II:贪心策略下的最少跳跃次数求解

一、问题定义与核心挑战

1.1 问题描述

给定一个非负整数数组 nums,你最初位于数组的第一个下标。数组中的每个元素 nums[i] 表示你在该位置可以跳跃的最大长度。你的目标是使用最少的跳跃次数到达数组的最后一个下标。假设你总能到达数组的最后一个下标。

1.2 核心特征与难点

  • 最优性要求:不仅要判断可达性,还要找到最少跳跃次数
  • 跳跃规则:从位置 i 可跳到 i+1i+nums[i] 之间的任意位置
  • 贪心选择:如何在每一步选择最优的跳跃点以最小化总次数

示例

  • 输入:nums = [2,3,1,1,4]
  • 输出:2(最优路径:0→1→4,两次跳跃)

二、解题思路:基于覆盖范围的贪心策略

2.1 核心思想

通过跟踪当前覆盖范围下一步最大覆盖范围,在每次到达当前覆盖范围的边界时进行跳跃,从而保证每次跳跃都是最优的:

  • 当前覆盖范围(cover):当前跳跃所能到达的最远位置
  • 下一步最大覆盖范围(maxCover):在当前覆盖范围内,所有位置能到达的最远位置
  • 跳跃时机:当遍历到当前覆盖范围的边界时,必须进行一次跳跃,此时将当前覆盖范围更新为下一步最大覆盖范围

2.2 直观理解

把跳跃过程想象成多阶段冲刺:

  1. 第一阶段:从起点出发,能到达的范围是 [0, cover],在这个范围内寻找能跳得最远的点,确定下一阶段的最大范围 maxCover
  2. 当到达第一阶段的边界(i = cover)时,必须跳一次,进入第二阶段,此时 cover 更新为 maxCover
  3. 重复上述过程,直到覆盖范围包含终点

三、代码逐行解析

3.1 边界条件处理

if (nums.length == 1) {return 0;  // 只有一个元素时,无需跳跃
}

3.2 核心变量定义

int cover = 0;       // 当前覆盖范围的边界
int maxCover = 0;    // 下一步能到达的最大覆盖范围
int cnt = 0;         // 跳跃次数

3.3 遍历与跳跃逻辑

for (int i = 0; i < nums.length; i++) {// 持续更新下一步能到达的最大覆盖范围maxCover = Math.max(i + nums[i], maxCover);// 当到达当前覆盖范围的边界,且能跳得更远时if (i == cover && maxCover > cover) {cover = maxCover;  // 更新覆盖范围cnt++;             // 跳跃次数加1// 若已覆盖终点,提前返回if (cover >= nums.length - 1) {return cnt;}}
}

3.4 返回结果

return cnt;

四、算法执行过程演示

nums = [2,3,1,1,4] 为例:

索引 i当前元素 nums[i]maxCover 计算关键操作covercnt
02max(0+2=2, 0) = 2-00
13max(1+3=4, 2) = 4-00
21max(2+1=3, 4) = 4i=2 == cover=0?不00
31max(3+1=4, 4) = 4i=3 == cover=0?不00
44max(4+4=8, 4) = 8i=4 == cover=0?是
maxCover>cover → 更新 cover=4,cnt=1
cover≥4(终点)→ 返回 1?
41

注意:实际执行中,当 i=2 时已经满足 i==cover(0),此时会触发跳跃:

  • 在 i=2 时,i==cover(0)且 maxCover=4>0 → cover=4,cnt=1
  • 此时 cover=4 已包含终点(4),直接返回 cnt=1?

修正演示:

  • i=0 时,maxCover=2
  • i=1 时,maxCover=4
  • i=2 时,i==cover(0)→ 触发跳跃,cover=4,cnt=1,此时 cover≥4 → 返回 1

最终结果为 2?不,正确结果应为 2,这里需要更精确的步骤分析:

正确步骤:

  1. 初始状态:cover=0,maxCover=0,cnt=0
  2. i=0:
    • maxCover = max(0+2, 0) = 2
    • i != cover(0==0),但需判断是否更新
    • 此时 i==cover 且 maxCover>cover → cover=2,cnt=1
  3. i=1:
    • maxCover = max(1+3=4, 2) =4
  4. i=2:
    • icover(22)
    • maxCover=4>2 → cover=4,cnt=2
    • 此时 cover≥4(终点)→ 返回 2

五、核心逻辑深度解析

5.1 为什么在 i == cover 时跳跃?

i == cover 表示已到达当前跳跃能覆盖的最远距离,此时必须进行下一次跳跃才能继续前进。选择此时跳跃能保证每次跳跃都是必要的,且跳跃范围是当前能达到的最大可能,从而最小化跳跃次数。

5.2 为什么 maxCover 能保证最优性?

maxCover 记录了当前覆盖范围内所有位置能到达的最远距离,选择这个范围作为下一次跳跃的覆盖范围,确保了每次跳跃都能到达最远的位置,从而减少总跳跃次数。

5.3 为什么无需考虑具体跳跃到哪个位置?

贪心算法的核心是“只关注范围不关注具体点”。只要知道下一次能覆盖的最大范围,就能确定最少跳跃次数,无需记录具体跳到哪个位置。

六、算法复杂度分析

  • 时间复杂度:O(n),只需遍历数组一次
  • 空间复杂度:O(1),仅使用常数个变量

七、常见误区与优化说明

7.1 误区1:在每次循环中都尝试跳跃

错误地在每个位置都进行跳跃判断,会导致跳跃次数过多。正确做法是只在到达当前覆盖范围边界时才跳跃。

7.2 误区2:忽略 maxCover > cover 的判断

如果没有这个判断,当无法跳得更远时(如 nums = [0,0,0]),会错误地增加跳跃次数。

7.3 优化点:提前终止循环

cover 已覆盖终点时,可立即返回结果,无需遍历剩余元素。

八、总结:贪心策略的跳跃优化

本题的贪心解法通过跟踪覆盖范围实现了最少跳跃次数的求解,核心在于:

  1. 区分当前覆盖范围和下一步最大覆盖范围
  2. 在适当的时机(到达当前范围边界)进行跳跃
  3. 每次跳跃都选择能到达的最远范围

这种策略确保了每一步都是最优的,从而在整体上得到最少的跳跃次数。掌握这种基于范围的贪心思想,可有效解决类似的优化路径问题。

代码的关键在于通过两个变量 covermaxCover 分别跟踪当前覆盖范围和下一步能到达的最大范围,在到达当前范围边界时进行跳跃并更新范围,从而保证每次跳跃都是最优的,最终得到最少的跳跃次数。

http://www.xdnf.cn/news/1320859.html

相关文章:

  • 机器学习的多种算法
  • 【数据集】全球大气监测计划(GAW)简介
  • AR技术为消防救援装上“智能透视眼”
  • 算法-决策树
  • Kafka的ISR、OSR、AR详解
  • 特赞内容运营解决方案,AI重构品牌内容价值链
  • 普通用户使用docker命令
  • 信创产业:从技术突围到生态重构的强国之路
  • 华曦达港股IPO观察丨以创新研发为笔,构建AI Home智慧生活新蓝图
  • Apache IoTDB集群部署实战:1C2D架构的高性能时序数据库搭建与优化指南
  • 静配中心配药智能化:基于高并发架构的Go语言实现
  • 十年回望:Vue 与 React 的设计哲学、演进轨迹与生态博弈
  • fit函数
  • Topaz Gigapixel AI:图片无损放大,细节增强的利器
  • LeetCode100 -- Day1
  • 【Linux指南】gcc/g++编译器:从源码到可执行文件的全流程解析
  • leetcode面试笔试-双指针题型总结
  • linux下查看 UDP Server 端口的启用情况
  • Redis 客户端接口介绍
  • Redis——基础篇
  • 【redis、ruoyi-vue】基于ruoyi-vue实现数据redis的增删改查
  • Java面试宝典:Redis高级特性和应用(发布 订阅、Stream)
  • [python学习记录1]python简介
  • 最小路径和
  • 在职老D渗透日记day19:sqli-labs靶场通关(第26a关)get布尔盲注 过滤or和and基础上又过滤了空格和注释符 ‘)闭合
  • 线程(基本概念和相关命令)
  • LeetCode热题100--104. 二叉树的最大深度--简单
  • Rust:实现仅通过索引(序数)导出 DLL 函数的功能
  • STM32单片机学习日记
  • 网络常识-SSE对比Websocket