frog jump

题目来源 leetcode 403
青蛙要过条河,河被分为n个区域,每个区域要么是水,要么是岩石。现在青蛙在第一块岩石上,它要通过不断跳跃到岩石上来到达最后一块岩石以渡河。青蛙最先开始只能跳跃过一个区域,若一次跳跃跳跃了k格,那么青蛙下一次跳跃只能跳跃k-1或k或k+1格,并且青蛙只能向前跳跃。给定一个stones数组,用于表示岩石的位置。例如[0,1,3,5,6,8,12,17]表示岩石分别在0,1,3,5,6,8,12,17号区域。而青蛙可以通过依次跳上0,1,3,5,8,12,17来渡河。容易发现如果岩石的位置不佳,青蛙不一定能够渡河。问题便是给出一组岩石位置,求解青蛙是否能成功渡河。
这个问题可以用动态规划的思想来解决。用布尔数组dp[n][m]表示青蛙在第n块岩石跳跃m格之后继续跳跃能否成功渡河。对于上面的例子dp[1][1]就为真,因为青蛙从0位置跳到1位置之后,继续跳跃可以渡河,然而dp[3][3]j就为假,因为青蛙在3位置如果直接跳到6位置,那么之后无论青蛙如何跳跃,都无法成功渡河。注意到对于dp[n][m],只有当m小于等于n的时候才是有意义的,因为青蛙跳到第n块石头上时,其下一次跳跃最多也只能跳跃n格。显然,根据题目条件,我们要求解的就是dp[1][1]。我们还可以推知,dp[n][k](0<=k<=n)为真。那么,我们可以考虑由dp[n][k]倒推至dp[1][1]。

考虑青蛙在第i块石头的情况。我们可以从最后一块石头开始向第i块石头扫描,依次判断当前石头与第i块石头的距离是否小于等于i,若是,则就可以更新dp[i][k],其中k为当前石头与第i块石头的距离。因为这个时候,青蛙可以尝试从第i块石头跳跃k步至之后的某块石头j,再根据j的情况判断是否可以成功渡河。状态转移方程为dp[i][k]=dp[j][k-1]||dp[j][k]||dp[j][k+1]。对于石头j处跳跃k-1,k,k+1步这三种情况,只要有一种情况可以到达终点,就表明从i跳跃k步可以到达终点。状态数O(n^2),处理状态时间复杂度为O(1)。总时间复杂度为O(n^2)。

bool canCross(vector<int>& stones) {
	vector<vector<bool> > dp(stones.size()+1);
	for (int i = 1; i < stones.size() + 1; i++)
	{
		dp[i] = vector<bool>(i + 1, 0);
	}
	for (int i = 0; i < dp[stones.size()].size(); i++)
	{
		dp[stones.size()][i] = 1;
	}
	for (int i = stones.size()-1; i >= 1; i--)
	{
		for (int j = stones.size(); j>i; j--)
		{
			if (stones[j - 1] - stones[i - 1] < dp[i].size())
			{
				if (!dp[i][stones[j - 1] - stones[i - 1]])
				{
					dp[i][stones[j - 1] - stones[i - 1]] = dp[j][stones[j - 1] - stones[i - 1]] || dp[j][stones[j - 1] - stones[i - 1] - 1] || dp[j][stones[j - 1] - stones[i - 1] + 1];
				}
				
			}
		}
	}
	return dp[1][1];
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值