【动态规划】C++算法:403.青蛙过河

这篇具有很好参考价值的文章主要介绍了【动态规划】C++算法:403.青蛙过河。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者推荐

视频算法专题

本文涉及知识点

动态规划汇总

LeetCode:403 青蛙过河

一只青蛙想要过河。 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有)。 青蛙可以跳上石子,但是不可以跳入水中。
给你石子的位置列表 stones(用单元格序号 升序 表示), 请判定青蛙能否成功过河(即能否在最后一步跳至最后一块石子上)。开始时, 青蛙默认已站在第一块石子上,并可以假定它第一步只能跳跃 1 个单位(即只能从单元格 1 跳至单元格 2 )。
如果青蛙上一步跳跃了 k 个单位,那么它接下来的跳跃距离只能选择为 k - 1、k 或 k + 1 个单位。 另请注意,青蛙只能向前方(终点的方向)跳跃。
示例 1:
输入:stones = [0,1,3,5,6,8,12,17]
输出:true
解释:青蛙可以成功过河,按照如下方案跳跃:跳 1 个单位到第 2 块石子, 然后跳 2 个单位到第 3 块石子, 接着 跳 2 个单位到第 4 块石子, 然后跳 3 个单位到第 6 块石子, 跳 4 个单位到第 7 块石子, 最后,跳 5 个单位到第 8 个石子(即最后一块石子)。
示例 2:
输入:stones = [0,1,2,3,4,8,9,11]
输出:false
解释:这是因为第 5 和第 6 个石子之间的间距太大,没有可选的方案供青蛙跳跃过去。
参数范围
2 <= stones.length <= 2000
0 <= stones[i] <= 231 - 1
stones[0] == 0
stones 按严格升序排列

动态规划

理论时间复杂度😮(nn)。
dp[i]记录所有能够从j跳到i的i-j,即k。
共有O(nn)种状态,故空间复杂度是O(nn),每种状态的转移方程时间复杂度O(1),故总时间复杂度O(nn)。

动态规划的细节,方便检查

动态规划的状态表示 dp[i]记录所有能够从j跳到i的i-j,即k
动态规划的转移方程 对于d[i]中的任意k,看是否存在石头stone[i]+i-1 ,stone[i]+i,stone[i]+i+1,如果存在,则可以跳到此石头。
动态规划的初始状态 dp[0]不会被使用,所以不用初始化。dp[1]有一个元素1
动态规划的填表顺序 i从小到大。因为只能从小到大跳,可以,确保动态规划的无后效性
动态规划的返回值 dp.back()。size()

超时代码

class Solution {
public:
bool canCross(vector& stones) {
if (1 != stones[1])
{
return false;
}
m_c = stones.size();
std::unordered_map<int, int> mValueIndex;
for (int i = 0; i < stones.size(); i++)
{
mValueIndex[stones[i]] = i;
}
vector<vector> dp(m_c);
dp[1].emplace_back(1);
for (int i = 1; i < m_c; i++)
{
for (const auto& k : dp[i])
{
for (int j = max(k - 1, 1); j <= k + 1; j++)
{
const int iNewValue = stones[i] + j;
if (mValueIndex.count(iNewValue))
{
dp[mValueIndex[iNewValue]].emplace_back(j);
}
}
}
}
return dp.back().size();
}
int m_c;
};

不超时代码

超时原因dp[i]中有重复值,用unorder_set除掉重复。
class Solution {
public:
bool canCross(vector& stones) {
if (1 != stones[1])
{
return false;
}
unordered_map<int, int> mPosToIndex;
for (int i = 2; i < stones.size(); i++)
{
mPosToIndex[stones[i]] = i;
}
vector<unordered_set> vPosK(stones.size());
vPosK[1].insert(1);
int k = 1;
for (int i = 1; i < stones.size(); i++)
{
if (stones.size() - 1 == i)
{
return vPosK[i].size();
}
for (auto& k : vPosK[i])
{
int iNewPos = stones[i] + k - 1;
if (mPosToIndex.end() != mPosToIndex.find(iNewPos))
{
vPosK[mPosToIndex[iNewPos]].insert(k - 1);
}
iNewPos++;
if (mPosToIndex.end() != mPosToIndex.find(iNewPos))
{
vPosK[mPosToIndex[iNewPos]].insert(k );
}
iNewPos++;
if (mPosToIndex.end() != mPosToIndex.find(iNewPos))
{
vPosK[mPosToIndex[iNewPos]].insert(k+1);
}
}
}
return true;
}
};

进阶除掉重复

重复的原因 :dp[i]中有x1,x1+1,x1+2 。则x1+1 (x1+1) (x1+2)-1 三者重复。
当dp[j]中有重复的k,说明此时的i相同。由于k=j-i,i是严格递增的,所以k是递减的。由于k是有序的,所以相同的k是挨着一起的。只需要检查前一个元素是否相等,无需判断其它元素。可以在O(1)的时间中避免重复。

class Solution {
public:
	bool canCross(vector<int>& stones) {
		if (1 != stones[1])
		{
			return false;
		}
		m_c = stones.size();
		std::unordered_map<int, int> mValueIndex;
		for (int i = 0; i < stones.size(); i++)
		{
			mValueIndex[stones[i]] = i;
		}
		vector<vector<int>> dp(m_c);
		dp[1].emplace_back(1);
		for (int i = 1; i < m_c; i++)
		{
			for (const auto& k : dp[i])
			{
				for (int j = max(k - 1, 1); j <= k + 1; j++)
				{
					const int iNewValue = stones[i] + j;
					if (mValueIndex.count(iNewValue))
					{
						auto& v = dp[mValueIndex[iNewValue]];
						if (v.empty() || (v.back() != j))
						{
							v.emplace_back(j);
						}
					}
				}
			}
		}
		return dp.back().size();
	}
	int m_c;
};

另外一种方法

前面的方法:第一层循环枚举i,第二层循环枚举k。
下面的方法:第一层循环枚举i,第二层循环枚举j。

class Solution {
public:
	bool canCross(vector<int>& stones) {
		if (1 != stones[1])
		{
			return false;
		}
		m_c = stones.size();
		vector<unordered_set<int>> dp(m_c);
		dp[1].emplace(1);
		for (int i = 2; i < m_c; i++)
		{
			for (int j = 1 ; j < i ;j++ )
			{
				const int iSub = stones[i] - stones[j];
				if (dp[j].count(iSub - 1)|| dp[j].count(iSub)|| dp[j].count(iSub + 1) )
				{//从够从stones[j]跳到stones[i]
					dp[i].emplace(iSub);
				}	
			}
		}
		return dp.back().size();
	}
	int m_c;
};

【动态规划】C++算法:403.青蛙过河,# 算法题,算法,动态规划,c++,leetcode,青蛙过河,石子,前跳

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 **C+

+17**
如无特殊说明,本算法用**C++**实现。

【动态规划】C++算法:403.青蛙过河,# 算法题,算法,动态规划,c++,leetcode,青蛙过河,石子,前跳文章来源地址https://www.toymoban.com/news/detail-797534.html

到了这里,关于【动态规划】C++算法:403.青蛙过河的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划解决过河卒问题

    介绍: 在算法和编程领域,动态规划是一种常见的问题解决方法,通过将问题分解为子问题并存储其解决方案,来有效地解决复杂的计算问题。本篇博客将介绍如何使用动态规划解决过河卒问题,该问题涉及到在一个棋盘上,卒需要从起始点走到目标点,同时要避开对方的马

    2024年02月04日
    浏览(25)
  • 动态规划dp-过河卒

    A点有一个过河卒,需要走到目标B点。卒行走规则:可以向下、或者向右。同时在棋盘上的任一点有一个对方的马(如上图的 C 点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点。例如上图℃ 点上的马可以控制9个点(图中的P1,P2...P8和C)。卒不能通过对方马的控制点

    2024年04月11日
    浏览(23)
  • 动态规划--青蛙跳台阶

    斐波那契数列每次学都有不一样的体会,从最开始简单理解就是,一个找规律的游戏,就是更新数值,往后算就行了,但是,后来,用斐波那契数列理解递归算法,是一个很好的例子,由上向下计算,依次回溯,最后,没想到斐波那契数列还能和动态规划联系起来。当然,斐

    2024年02月19日
    浏览(21)
  • 石子合并问题(动态规划)

    石子合并问题是一个经典的动态规划问题,应用了最优子结构和重复子问题的思想。 (1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成 (动态规划)O(n^3) 设dp[i][j]表示将i至j之

    2024年02月06日
    浏览(32)
  • 合并石子(动态规划)

    首先理解题意,笔者看到这道题时首先想到的是贪心,仔细分析后发现题上没说石子根据一定顺序来摆放,易证局部最优解不一定是问题最优解,没有贪心性质,不能用贪心 然后需要强调的是,该题是一个圆形结构 这里为了方便理解,我们先将其简化为线性结构 先看一个简

    2024年02月01日
    浏览(28)
  • 【动态规划】之石子合并问题

    在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。请设计一个程序,计算出将N堆石子合并成一堆的最小得分和最大得分。 我们对n的取值逐步分析 当n=1时,没有进

    2024年04月28日
    浏览(24)
  • 动态规划——区间dp [石子合并]

    动态规划(dp)是一种通过将问题分解为子问题,并利用已解决的子问题的解来求解原问题的方法。适用于具有重叠子问题和最优子结构性质的优化问题。通过定义状态和状态转移方程,动态规划可以在避免重复计算的同时找到问题的最优解,是一种高效的求解方法,常用于

    2024年02月12日
    浏览(35)
  • 租用游艇问题 石子合并问题 动态规划实验

    实验名称:                动态规划                          一、实验预习 1、实验目的 1. 理解并掌握动态规划方法的设计思想; 2. 提高应用动态规划方法解决问题和设计算法的能力; 3. 通过编程实现租用游艇问题和石子合并问题,进一步理解动态规划方

    2024年02月07日
    浏览(34)
  • 石子合并(动态规划 区间DP)+详细注释

    原题链接   活动 - AcWing 题目 设有 N 堆石子排成一排,其编号为 1,2,3,…,N。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相

    2024年02月16日
    浏览(29)
  • Python动态规划——以“codeJan与青蛙”为例

    链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网         codeJan喜欢观察世界。有一天,codeJan发现一个非常奇怪的现象。有一些年轻的青蛙聚集在一条直线上的某些位置上,同一个位置可能有多个青蛙。这些青蛙每次只会向前跳一米,并且每只青蛙每跳一次都

    2024年02月02日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包