[Leetcode] 403. Frog Jump 解题报告

来源:互联网 发布:天津密云路五金城淘宝 编辑:程序博客网 时间:2024/05/21 22:40

题目

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.

思路

这道题目的难点在于状态之间的转移是有条件的:也就是从i跳跃到j,不仅取决于i到j之间的距离,而且取决于跳到i步的上一步所跳跃的距离,因此,普通的动态规划就不合适了。下面给出两种从前往后的搜索策略。

1、暴力DFS解法:也就是记录上一步跳跃的步数k,然后在本步中,试图跳跃k - 1, k, k+1,如果任意一种策略可以到达最后一块石头,则返回true;否则返回false。暴力解法的问题在于里面存在重复计算:例如在a->b->c的过程中,假设b->c跳跃了k步,但是a->b的过程既有可能跳跃了k-1步,也有可能跳跃了k+1步。所以b->c跳跃k步的情况就有可能在a->b的递推过程中被重复计算。因此这种算法不能通过所有的测试用例。

2、记录步长集合:注意到暴力DFS的问题,我们给每个石头记录一个步数集合,例如stones[i] = {1, 3, 5}即意味着从前面的某个石头跳跃1,3,5步可以到达stones[i]。这样的好处就是:通过stones[i]的步长集合,我们就可以递推出从stones[i]出发都可以跳跃到后面的哪些石头上。这样,只要判断最后一个石头的步数集合是否为空,就可以判断青蛙是否可以跳跃到这里了。

代码

1、暴力解法:

class Solution {public:    bool canCross(vector<int>& stones) {        if (stones.size() <= 1) {            return true;        }        if (stones[1] != 1) {            return false;        }        return canCross(stones, 1, 1);    }private:    bool canCross(vector<int>& stones, int position, int last_step) {        if (last_step <= 0 || position > stones.back()) {            return false;        }        else if (position == stones.back()) {            return true;        }        vector<int>::iterator it;        it = lower_bound(stones.begin(), stones.end(), position + last_step - 1);   // try to jump last_step - 1        if (it != stones.end() && *it == position + last_step - 1) {            if (canCross(stones, position + last_step - 1, last_step - 1)) {                return true;            }        }        it = lower_bound(stones.begin(), stones.end(), position + last_step);       // try to jump last_step        if (it != stones.end() && *it == position + last_step) {            if (canCross(stones, position + last_step, last_step)) {                return true;            }        }        it = lower_bound(stones.begin(), stones.end(), position + last_step + 1);   // try to jump last_step + 1        if (it != stones.end() && *it == position + last_step + 1) {            if (canCross(stones, position + last_step + 1, last_step + 1)) {                return true;            }        }        return false;    }};

2、记录步长集合:

class Solution {public:    bool canCross(vector<int>& stones) {        map<int, set<int>> jumps;         for(int i = 0; i < stones.size(); ++i) {            jumps[stones[i]] = {};          }          jumps[0].insert(0);          for(int i = 0; i < stones.size() - 1; ++i) {              int index = stones[i];              if(jumps[index].size() == 0) {      // can not reach here from previous stones                continue;              }            for(auto step : jumps[index]) {                for(int j = step - 1; j <= step + 1; ++j) {                      if(j <= 0) {                        continue;                    }                    if(jumps.find(index + j) != jumps.end()) {                        jumps[index + j].insert(j);                    }                }              }          }          return jumps[stones.back()].size() != 0;      }};

原创粉丝点击