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.
一个青蛙想要跳过河,河被分成x个单元,每个单元上可能存在着石头,青蛙只可以跳到这些石头上。现在给定一个递增的序列,代表石头的位置,判断青蛙能否跳到最后一个石头上。青蛙初始只能跳1个单元的距离,如果上一次起跳的距离为K,那么下一次起跳距离的为k-1,k或者k+1。青蛙只能向前跳。
思路:由于每次跳的长度只有3个可能,很容易可以想到通过枚举的方法列出所有可能判断能不能跳过去,通过暴力搜索的方法。但是这样做会超时,可以在搜索的时候用二分查找或者用将vector储存换成hash table储存提高搜索效率。显然,这并不是最好的解决方法。其实就是一个明显的dynamic programming的问题,刚好老师这星期就讲了这种类型的题目,对这道题目就迎刃而解了。用一个大小为n的数组代表每一个石头,再用n个set记录第i个石头能到达的石头集合,比如dp[0]的set为{1},因为从起点出发只能跳到距离为1的第一个单元上。遍历每一个石头a,对这个石头后面的每一个石头b检查一遍,计算之间的距离h。当前遍历的石头a对应有一个集合,是能直接跳到的石头的距离的集合,将集合里的距离与a和b之间的距离h进行比较,如果距离大于h+1,则继续搜索,因为序列是递增的,下一个距离肯定会变小。如果距离小于h-1,则停止搜索,因为下一个距离会更加小,不可能跳到比h-1还小的距离。如果距离在[h-1,h+1]之间,则说明可以跳到这个石头b,在石头b的集合insert这个距离。遍历完所有的石头之后,只要检查第n个石头的集合是不是空的就可以判断能不能跳到第n个石头了。
class Solution {
public:
bool canCross(vector<int>& stones) {
if(stones[1] != 1) return false;//特殊情况判断
int n = stones.size();
vector<set<int>> dp(n);//二维数组记录能跳到的石头集合
dp[0].insert(1);
for(int i = 0; i < n; ++i)
{
for(int j = i+1; j < n; ++j)
{
int step = stones[j] - stones[i];//求出两个石头的实际距离
for(set<int>::iterator it = dp[i].begin(); it != dp[i].end(); ++it)
{
if(*it+1 < step)//如果距离大于k+1,继续搜索
continue;
if(*it-1 > step)//如果距离小于k-1,停止搜索
break;
dp[j].insert(step);//把能跳到的距离加入到集合
}
}
}
if(!dp[n-1].empty())
return true;
else
return false;
}
};