leetcode 403. Frog Jump 青蛙跳问题+典型深度优先遍历问题

A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.

Given a list of stones’ positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.

If the frog’s last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.

Note:

The number of stones is ≥ 2 and is < 1,100.
Each stone’s position will be a non-negative integer < 231.
The first stone’s position is always 0.
Example 1:

[0,1,3,5,6,8,12,17]

There are a total of 8 stones.
The first stone at the 0th unit, second stone at the 1st unit,
third stone at the 3rd unit, and so on…
The last stone at the 17th unit.

Return true. The frog can jump to the last stone by jumping
1 unit to the 2nd stone, then 2 units to the 3rd stone, then
2 units to the 4th stone, then 3 units to the 6th stone,
4 units to the 7th stone, and 5 units to the 8th stone.
Example 2:

[0,1,2,3,4,8,9,11]

Return false. There is no way to jump to the last stone as
the gap between the 5th and 6th stone is too large.

题目中说青蛙如果上一次跳了k距离,那么下一次只能跳k-1, k, 或k+1的距离,那么青蛙跳到某个石头上可能有多种跳法,由于这道题只是让我们判断青蛙是否能跳到最后一个石头上,并没有让我们返回所有的路径,这样就降低了一些难度。我们可以用递归来做,我们维护一个哈希表,建立青蛙在pos位置和拥有jump跳跃能力时是否能跳到对岸。为了能用一个变量同时表示pos和jump,我们可以将jump左移很多位并或上pos,由于题目中对于位置大小有限制,所以不会产生冲突。我们还是首先判断pos是否已经到最后一个石头了,是的话直接返回true;然后看当前这种情况是否已经出现在哈希表中,是的话直接从哈希表中取结果。如果没有,我们就遍历余下的所有石头,对于遍历到的石头,我们计算到当前石头的距离dist,如果距离小于jump-1,我们接着遍历下一块石头;如果dist大于jump+1,说明无法跳到下一块石头,m[key]赋值为false,并返回false;如果在青蛙能跳到的范围中,我们调用递归函数,以新位置i为pos,距离dist为jump,如果返回true了,我们给m[key]赋值为true,并返回true。如果结束遍历我们给m[key]赋值为false,并返回false

这道题需要学习的地方就是拼接Map的key值,有个博客中使用到了移位操作,但是其实可以直接使用字符串拼接,mmp[i]=true表示key i 是可以到达最后一块石头

代码如下:

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <queue>
#include <stack>
#include <string>
#include <climits>
#include <algorithm>
#include <sstream>
#include <functional>
#include <bitset>
#include <numeric>
#include <cmath>
#include <regex>
#include <iomanip>
#include <cstdlib>
#include <ctime>

using namespace std;


class Solution
{
public:
    bool canCross(vector<int>& stones)
    {
        map<string, bool> mmp;
        return dfs(stones, mmp, 0, 0);
    }

    bool dfs(vector<int>& s, map<string, bool>& mmp, int index, int lastjump)
    {
        string key = to_string(index) + "_" + to_string(lastjump);
        if (index >= s.size() - 1)
            return true;
        else if (mmp.find(key) != mmp.end())
            return mmp[key];
        else
        {
            for (int i = index + 1; i < s.size(); i++)
            {
                int len = s[i] - s[index];
                if (len >= lastjump - 1 && len <= lastjump + 1)
                {
                    if (dfs(s, mmp, i, len) == true)
                    {
                        mmp[key] = true;
                        return true;
                    }
                }
            }
            mmp[key] = false;
            return false;
        }
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值