前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode 403. 青蛙过河(DP)

LeetCode 403. 青蛙过河(DP)

作者头像
Michael阿明
发布2020-07-13 15:58:04
1K0
发布2020-07-13 15:58:04
举报

1. 题目

一只青蛙想要过河。 假定河流被等分为 x 个单元格,并且在每一个单元格内都有可能放有一石子(也有可能没有)。 青蛙可以跳上石头,但是不可以跳入水中

给定石子的位置列表(用单元格序号升序表示), 请判定青蛙能否成功过河(即能否在最后一步跳至最后一个石子上)。 开始时, 青蛙默认已站在第一个石子上,并可以假定它第一步只能跳跃一个单位(即只能从单元格1跳至单元格2)。

如果青蛙上一步跳跃了 k 个单位,那么它接下来的跳跃距离只能选择为 k - 1、k 或 k + 1个单位。 另请注意,青蛙只能向前方(终点的方向)跳跃。

请注意: 石子的数量 ≥ 2 且 < 1100; 每一个石子的位置序号都是一个非负整数,且其 < 231; 第一个石子的位置永远是0。

代码语言:javascript
复制
示例 1:
[0,1,3,5,6,8,12,17]
总共有8个石子。
第一个石子处于序号为0的单元格的位置, 第二个石子处于序号为1的单元格的位置,
第三个石子在序号为3的单元格的位置, 以此定义整个数组...
最后一个石子处于序号为17的单元格的位置。
返回 true。即青蛙可以成功过河,按照如下方案跳跃: 
跳1个单位到第2块石子, 然后跳2个单位到第3块石子, 接着 
跳2个单位到第4块石子, 然后跳3个单位到第6块石子, 
跳4个单位到第7块石子, 最后,跳5个单位到第8个石子(即最后一块石子)。

示例 2:
[0,1,2,3,4,8,9,11]
返回 false。青蛙没有办法过河。 
这是因为第5和第6个石子之间的间距太大,没有可选的方案供青蛙跳跃过去。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/frog-jump 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 动态规划

在这里插入图片描述
在这里插入图片描述
  • dp数组,存储一个set,set中存储前一格是跳多少步step过来的(可能有多种方案,需要去除同样步数过来的)
  • 走到一格以后,根据当前step,向前试探 k-1,k,k+1 步,看在不在石头上
  • 在石头上,则将走的步数插入到该位置的集合中
代码语言:javascript
复制
class Solution {
public:
    bool canCross(vector<int>& stones) {
        unordered_map<int,int> m;//存储distance、对应的下标
        int i, j, k, n = stones.size(), len;
        if(stones[1] != 1)//题目意思是,第一步只能走1个distance
            return false;
        for(i = 0; i < n; ++i) 
        	m[stones[i]] = i;
        // int dp[n] = {0};//存储到达一块石头时,一次跨多少步过来的(不可以用一维数组)
        vector<unordered_set<int>> dp(n);//可能有多种跳到过来的方法,对后面的k有影响
        unordered_set<int>::iterator it;
        dp[1].insert(1);
        int delta[3] = {-1,0,1};//前进的增量
        int distance, step;
        for(i = 1; i < n; ++i)
        {
        	len = dp[i].size();
            if(len > 0)//跳过来的方案数存在
            {
                for(j = 0; j < 3; ++j)//每个方案有3种增量前进
                {
                	for(it = dp[i].begin(); it != dp[i].end(); ++it)
                	{	//遍历每个方案(前面多少步跳过来的)
	                	step = *it+delta[j];
	                	distance = stones[i]+step;//可到的距离
	                    if(step > 0 && m.count(distance))//方向是向前的,且 在石头上
	                        dp[m[distance]].insert(step);//将多少步过去的记录在那个石头上
	                }
                }
            }
        }
        return dp[n-1].size()>0;//有方案可以到达最后一个石头
    }
};
在这里插入图片描述
在这里插入图片描述

别人的解法总是这么优雅

代码语言:javascript
复制
class Solution {
public:
    bool canCross(vector<int>& stones) {
        bool dp[1101][1101];//dp[位置][步长],表示第i个石头,步长,可以到它那里吗
        memset(dp, false, sizeof(dp));
        dp[0][0] = true;
        int gap, i;
        for(i = 1; i < stones.size(); i++) 
        {
            for(int j = 0; j < i; j++) 
            {
                gap = stones[i] - stones[j];//前面的石头跟我比有多远
                if(gap >= 1100) continue;
                if(dp[j][gap] || dp[j][gap + 1] || (gap > 0 && dp[j][gap - 1]))
                    dp[i][gap] = true;
            }
        }
        for(i = 0; i < stones.size(); i++)
            if(dp[stones.size() - 1][i])
                return true;
        return false;
    }
};
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 题目
  • 2. 动态规划
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档