LeetCode 算法:跳跃游戏 c++

devtools/2024/9/22 19:50:28/
  • 原题链接🔗:跳跃游戏
  • 难度:中等⭐️⭐️

题目

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

示例 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 <= 104
  • 0 <= nums[i] <= 105

动态规划

动态规划(Dynamic Programming,简称DP)是一种算法思想,用于解决具有重叠子问题和最优子结构特性的问题。它通过将问题分解为更小的子问题,并存储这些子问题的解(通常是在表格中),来避免重复计算,从而提高算法效率。

动态规划的关键步骤:

  1. 识别子问题:将原问题分解为一系列子问题,这些子问题通常是原问题规模更小的版本。

  2. 确定状态:定义状态变量,通常用一个或多个变量来表示问题的某一阶段的状态。

  3. 状态转移方程:找到状态之间的关系,即当前状态是如何由之前的一个或多个状态推导出来的。

  4. 确定边界条件:确定递推的起始点,也就是基本情况(base case)。

  5. 计算顺序:确定计算状态的顺序,以确保在计算当前状态之前,所需的所有状态都已经被计算过。

  6. 构造最优解:根据状态转移方程和边界条件,从基本情况开始,逐步构建解决方案。

动态规划的类型:

  1. 自顶向下的递归方法(Memoization):从原问题开始,逐步分解为子问题,使用递归计算,并存储已经计算过的子问题的结果以避免重复计算。

  2. 自底向上的迭代方法:从基本情况开始,逐步向上计算直到原问题的状态,通常使用循环和表格来实现。

动态规划的应用领域:

  • 优化问题:如最短路径、最小花费、最大收益等。
  • 计数问题:计算不同选择的数量。
  • 组合问题:如切割问题、背包问题等。

示例:斐波那契数列(自底向上方法)

斐波那契数列是一个经典的动态规划问题,可以通过以下步骤解决:

  1. 状态定义F(n) 表示斐波那契数列的第 n 项。

  2. 状态转移方程F(n) = F(n-1) + F(n-2)

  3. 边界条件F(0) = 0F(1) = 1

  4. 计算顺序:从 n = 2n

  5. 代码实现

int fibonacci(int n) {if (n <= 1) return n;int dp[n + 1]; // 创建一个大小为 n+1 的数组dp[0] = 0;dp[1] = 1;for (int i = 2; i <= n; ++i) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[n];
}

动态规划是一种强大的算法设计技术,适用于解决许多类型的问题。掌握动态规划需要大量的练习和对问题结构的深入理解。

贪心算法

贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法策略。贪心算法不保证会得到最优解,但在某些问题中,贪心算法的解是足够好的,或者在性能上是可接受的。

贪心算法的关键特点:

  1. 贪心选择性质:在每一步选择中都采取当前状态下的最优选择。
  2. 无回溯:一旦进行选择,就不再回溯,即不重新考虑之前的选择。
  3. 子问题最优:局部最优选择可能导致全局最优解。
  4. 可行性:选择的每一步必须是可行的。

贪心算法的适用场景:

  • 当问题具有最优子结构时,即问题的最优解包含子问题的最优解。
  • 当问题可以通过贪心选择性质来解决时。

贪心算法的步骤:

  1. 问题定义:明确问题的目标和约束条件。
  2. 贪心选择:确定每一步的贪心选择标准。
  3. 可行性检验:确保每一步的选择都是可行的。
  4. 构造解决方案:按照贪心选择逐步构造解决方案。

示例:硬币找零问题

假设有无限数量的硬币,面额分别为1元、2元和5元,需要找零金额为n元。贪心算法的思路是尽可能多地使用面额最大的硬币。

  1. 贪心选择:尽可能多地使用5元硬币。
  2. 状态更新:剩余金额减去5元硬币的面额。
  3. 重复:直到剩余金额小于5元。
  4. 继续贪心选择:然后尽可能多地使用2元硬币。
  5. 最终:使用1元硬币补足剩余金额。

代码实现:

#include <iostream>
#include <vector>void coinChange(std::vector<int>& coins, int n) {int count = 0;for (int i = coins.size() - 1; i >= 0; --i) {count += n / coins[i];n %= coins[i];}std::cout << "Minimum coins needed: " << count << std::endl;
}int main() {std::vector<int> coins = {1, 2, 5};coinChange(coins, 11); // 输出应该是 3 (5 + 5 + 1)return 0;
}

贪心算法简单且易于实现,但在使用时需要仔细考虑问题是否适合使用贪心策略。有些问题,如旅行商问题(TSP)或背包问题(Knapsack Problem),贪心算法可能无法得到最优解,而需要使用动态规划或其他更复杂的算法

题解

  1. 解题思路:

LeetCode 上的 “跳跃游戏” 问题是一个典型的动态规划问题。这个问题的描述是:给定一个非负整数数组,表示每个位置可以跳跃的最大长度,判断从数组的开始位置出发,能否到达数组的最后一个位置。

  • 问题背景
    假设有一个数组 nums,其中 nums[i] 表示从位置 i 可以跳到 i + nums[i] 的位置。如果 i + nums[i] 大于或等于数组的长度,则表示可以跳出数组。

  • 解题思路

    • 贪心算法:这是解决这个问题的一种方法。我们可以从数组的开始位置开始,每次跳到能够到达的最远位置。然后,从这个新位置继续这个过程,直到到达或超过数组的最后一个位置。

    • 动态规划:另一种方法是使用动态规划。我们可以创建一个布尔数组 dp,其中 dp[i] 表示从位置 i 是否能够到达数组的末尾。然后,我们可以从后向前填充这个数组,因为我们知道从最后一个位置可以到达末尾。

    • 一次遍历:在贪心算法的基础上,我们可以进一步优化,只进行一次遍历。我们维护两个变量,maxReach 表示当前能够到达的最远位置,end 表示数组的末尾。在遍历过程中,如果当前位置加上可以跳的距离大于 maxReach,则更新 maxReach。如果 maxReach 大于或等于 end,则表示可以到达末尾。

  1. c++ demo:
#include <iostream>
#include <vector>bool canJump(std::vector<int>& nums) {int maxReach = 0, i = 0;while (i < nums.size()) {if (i > maxReach) return false; // 如果当前索引超过了能到达的最远距离,则无法到达末尾maxReach = std::max(maxReach, i + nums[i]); // 更新能到达的最远距离i++; // 移动到下一个可以跳的位置}return true; // 如果遍历完成,说明可以到达末尾
}int main() {std::vector<int> nums1 = { 2, 3, 1, 1, 4 };std::cout << (canJump(nums1) ? "true" : "false") << std::endl; // 应该输出 truestd::vector<int> nums2 = { 3, 2, 1, 0, 4 };std::cout << (canJump(nums2) ? "true" : "false") << std::endl; // 应该输出 falsestd::vector<int> nums3 = { 0 };std::cout << (canJump(nums3) ? "true" : "false") << std::endl; // 应该输出 truereturn 0;
}
  1. 代码仓库地址: canJump

http://www.ppmy.cn/devtools/99786.html

相关文章

独孤思维:我找到了可以一辈子赚钱的项目

01 独孤自从参与短文写作项目的教练以后。 有一个非常大的感慨。 没想到一个小教练&#xff0c;其实发挥的作用&#xff0c;要做的事情&#xff0c;远比自己想象的要多。 这并不是抱怨。 而是能够从这次教练&#xff0c;再次深刻理解交付的重要性。 学员不知道写什么&…

Docker Desktop镜像路径修改一直报错

一 点击Apply & Restart报错 [Window Title] Docker Desktop[Main Instruction] Error migrating WSL disk[Content] An error occurred while migrating the Docker Desktop WSL data disk to its new location:moving disk file: rename C:\Users\Lenovo\AppData\Local\D…

StarRocks 存算分离数据回收原理

前言 StarRocks存算分离表中&#xff0c;垃圾回收是为了删除那些无用的历史版本数据&#xff0c;从而节约存储空间。考虑到对象存储按照存储容量收费&#xff0c;因此&#xff0c;节约存储空间对于降本增效尤为必要。 在系统运行过程中&#xff0c;有以下几种情况可能会需要删…

空状态设计教程:连接用户体验的桥梁

空状态设计是产品设计中常被忽视却又极其重要的一环。它不仅是用户旅程的起点&#xff0c;更是塑造第一印象的关键。本文将引导你如何使用强大的设计工具设计出既美观又实用的空状态&#xff0c;以提升用户体验。 空状态设计的意义 空状态作为用户与产品初次邂逅的界面&#…

洛谷p1168中位数题解

题目描述 给定一个长度为 N 的非负整数序列 A&#xff0c;对于前奇数项求中位数。 输入格式 第一行一个正整数 N。 第二行 N 个正整数 A1…N。 输出格式 共 ⌊(N1)/2⌋ 行&#xff0c;第 i 行为 A1…2i−1的中位数。 输入输出样例 输入 #1复制 7 1 3 5 7 9 11 6 输出…

详解华为项目管理,附华为高级项目管理内训材料

&#xff08;一&#xff09;华为在项目管理中通过有效的沟通、灵活的组织结构、坚持不懈的努力、细致的管理和科学的考核体系&#xff0c;实现了持续的创新和发展。通过引进先进的管理模式&#xff0c;强调以客户需求为导向&#xff0c;华为不仅优化了技术管理和项目研发流程&a…

每天一个数据分析题(四百八十九)- 主成分分析与因子分析

关于主成分分析和因子分析的区别&#xff0c;下列描述正确的是&#xff08; &#xff09; A. 主成分分析是一种无监督学习算法&#xff0c;而因子分析是一种有监督学习算法 B. 主成分分析是一种线性变换方法&#xff0c;而因子分析是一种非线性变换方法 C. 主成分分析的结果…

12、stm32通过dht11读取温湿度

一、配置 二、代码 dht11.c /** dht11.c** Created on: Aug 19, 2024* Author: Administrator*/#include "main.h" #include "tim.h" #include "usart.h" #include "gpio.h" /**TIM3定时器实现us级延时*/ void Delay_us(uint16…