题意:给出石头的位置,然后青蛙每一跳的距离a和上一跳距离k满足(k==a||k==a-1||k==a+1),第一个石头是位置0,第一跳只能距离为1.
分析与思路:这个题目用遍历搜索所有的路线是肯定可以做的,但是简单的遍历会超时,我用的方法是深度优先遍历同时排除掉不可能的情况。我用一个数据结构step来保存当前位置以及跳到这里的上一跳距离,我用一个优先队列(位置靠后的优先)保存所有出现过的step,同时要排除一些不可能情况,我排除的不可能情况在注释中已表明。
代码:
class step {//每一步的有关数据
public:
int nowStone = 0;
int lastdis = 0;
step(int a, int b) {
lastdis = b;
nowStone = a;
}
};
struct cmp {//优先队列的比较函数
bool operator()(const step a, const step b) {
return a.nowStone < b.nowStone;
}
};
const int MAXSTEP = pow(2, 31) / 1000;
/*最长步距,最多1100个数据,最大值是pow(2, 31),所以满足条件的情况不可能有一步会超过这个值,
因为必须从一开始的1慢慢增到pow(2, 31),最少的步长要为pow(2, 31) / 1100,所以不妨放到除以1000,*/
class Solution {
public:
bool canCross(vector<int>& stones) {
if (stones.size() == 2) {//特殊情况
if (stones[0] == 0 && stones[1] == 1) return true;
else return false;
}
priority_queue<step,vector<step>,cmp> steps;
steps.push(step(1, 1));//初始化
int maxdis = 1;//记录在队列中出现过的满足条件的最长步距
while (!steps.empty()) {
step nowsteps = steps.top();
steps.pop();
int count = 3;//每一步的下一步最多有三种满足条件的情况
for (int i = nowsteps.nowStone+1; i < stones.size(); i++) {
if (stones[i] - stones[nowsteps.nowStone] > MAXSTEP) return false;//防止出现极端值
if (stones[i] - stones[nowsteps.nowStone] > nowsteps.lastdis + 1) break;
//出现了超过这个值以后的情况都不用考虑能作为当前步的下一步
if (stones[i] - stones[nowsteps.nowStone] > maxdis + 1) return false;
//出现了超过队列中出现的最长步距则说明不可能还能延续下去,可以终止了
if (stones[i]-stones[nowsteps.nowStone] == nowsteps.lastdis
|| stones[i]-stones[nowsteps.nowStone] == nowsteps.lastdis + 1
|| stones[i]-stones[nowsteps.nowStone] == nowsteps.lastdis - 1) {
count--;
if (stones[i] - stones[nowsteps.nowStone] > maxdis) maxdis = stones[i] - stones[nowsteps.nowStone];//更新
steps.push(step(i,stones[i]-stones[nowsteps.nowStone]));
if (i == stones.size()-1) return true;//找到目标
if (count == 0) break;
}
}
}
return false;
}
};