dynamic programming again!可能是这个问题太复杂了吧,老师讲了好几周了,然而我却还是不能很好的理解这中思想,感觉就是遍历。回到正题,这次的选题比较果断,选定后就没有改了,死磕,然后我懵了。下面看题目吧。
--------------------下面是题目---------------------------
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.-------------------------------题解-----------------------------------
虽然很不好意思承认,但一开始这题目就把我看懵了,对照着example1慢慢看才把题目勉强理解。可以理解为一条河宽x米,有一些石头分布在河里面,将给出一个数组来表明这些石头的位置,拿example1来说的话就是在起点,1米处,3米处,5米处,6米处,8米处,12米处,17米处有石头,一只青蛙想要过河,虽然青蛙可以游泳,但题目要求只能踩着石头过河,而且有一个要求是如果青蛙上一次跳了k米,那么这一次就只能跳k-1,k或者k+1米,如果最后可以跳到最后一块石头上就返回true,否者返回false,初始条件是第一次青蛙只能跳一米。理解完题目后我们来思考要怎么解决了,我一开始的想法是,从前往后遍历,青蛙到了一块石头肯定是从前面的某一块石头跳到这一块石头上的,但我们不知道上一块石头具体是那一块,有可能有多块石头都可以到,所以建一个映射,用于记录石头的位置,以及到达这块石头时的上一跳跳了多远,第二个元素用一个集合来记录。最后看对应最后一块石头的映射,如果说上一跳距离的集合是空集那么就说明不能达到最后一块,如果有元素的话就说明能通过前面的某一块石头作为跳板到达。然而这么完美的思路竟然超时了,其实想想也就O(n^2)的时间复杂度吧,然后我就没办法了,看了看大神们的题解,发现大部分人都是用dfs做的,我想请问一下,为什么要把一道用动归超时的题放在动态规划里面,好吧,可能是我的算法有问题,但是以我的水平是没办法优化了,照着大神们的思路做了一遍。dfs的思路也是建一个映射,不过映射变成了当前位置到所有可能的下一跳的映射,这样一来就一定会知道能不能到最后一块石头的位置,毕竟这种方法遍历了所有可能的结果,时间复杂度差不多是O(n)吧,思路很简单,代码也不难。
--------------------------代码-----------------------------------
#include <iostream>
#include <map>
#include <vector>
#include <set>
using namespace std;
class Solution {
public:
bool canCross(vector<int>& stones) {
if(stones[1]!=1)
return false;
int l=stones.size();
map<int , set<int> >unit;
for(int i=0;i<l;i++) //初始化 表明有这些元素
{
unit[stones[i]].insert(0);
}
unit[0].insert(1);
for(int i=0;i<l-1;i++)
{
int p=stones[i];
for(set<int>::iterator it=unit[p].begin(); it!=unit[p].end(); ++it)
{
int val=*it;
if(val==0)
continue;
int newp=p+val;
if(newp==stones[l-1])
return true;
if(unit[newp].size()!=0)//添加所有可能的下一跳
{
unit[newp].insert(val);
if(val-1>0)
unit[newp].insert(val-1);
unit[newp].insert(val+1);
}
}
}
return false;
}
};
因为思路足够简单,所以代码也没什么好说的,自己辛辛苦苦想的动态规划超时了真的是怎么想怎么不爽啊,关键是最后大神的题解都没有用动态规划,最后的解决思路是dfs,都不让我死个明白,心累。无话可说。
-------------------------------手动分割线--------------------------------
see you next illusion