LeetCode题解(Week 8):403. Frog Jump

来源:互联网 发布:日本讨厌韩国知乎 编辑:程序博客网 时间:2024/06/06 11:41

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.

中文大意

经典的青蛙过河问题,有一个数组a={a1,a2,a3…,an},其中a1 = 0, 一只青蛙从a1出发,第一步走1个单位,青蛙过河有这样的规律:第k-1次如果跳了n个单位,那么第k次就只能跳n,n-1,n+1个单位,并且只能向前跳,问青蛙能否到达对岸(也就是跳到an)

题解

class Solution {public:    bool canCross(vector<int>& stones) {        int n = stones.size();        unordered_map<int, unordered_set<int>> dp;        dp[0].insert(0);        int maxdist = 0;        for(int i = 1 ;i < n;i++)        {            for(int j = 0;j<i;j++)            {                int currdist = stones[i] - stones[j];                //如果跳maxdist+1跳不到现在的这个石头,那就不用考虑j这块石头了                if(currdist > maxdist+1) continue;                if(dp[j].count(currdist)||dp[j].count(currdist-1)||dp[j].count(currdist+1))                {                    dp[i].insert(currdist);                    maxdist = max(currdist,maxdist);                }            }        }        return dp[n-1].size() > 0;    }};

思路

又是典型的动态规划问题了,状态分解的思路如下,记:

  • dp[i]等于“从上一块石头(不一定是i-1)跳到第i块石头,跳了多少步”
  • dist = stone[i] - stone[j]表示石头i与石头j之间的距离

这个时候,dp[i]可以通过dist以及dp[0…i-1]来得到:

  • 如果dp[j]其中(0 <= j < i) 的值刚好为dist,意味着青蛙可以从j跳dist个单位到达i,dp[i] = dist
  • 同理,如果dp[j]=dist-1,意味着青蛙可以从j跳dist个单位到达i,dp[i] = dist
  • 同理,有dp[j]=dist+1,dp[i] = dist

但是到达i的方式不唯一(可能存在多个j能够跳到i),因此需要用一个特定的结构(比如集合),将dp[i]中的每一个可能取值都存起来

但是!这样做是会超时的,因为时间复杂度不符合题目的要求,解决方法是通过一个数maxdist,来记录下当前青蛙跳过的最长距离,如果当前的距离dist(i,j)比这个最长距离加一还要大的话,意味着肯定不能从j跳到i了,直接continue

这样做的话,时间复杂度是O(n^2),空间复杂度接近O(n)

0 0
原创粉丝点击