LeetCode 中国,https://leetcode-cn.com/problems/minimum-jumps-to-reach-home/。
有一只跳蚤的家在数轴上的位置 x 处。请你帮助它从位置 0 出发,到达它的家。
跳蚤跳跃的规则如下:
它可以 往前 跳恰好 a 个位置(即往右跳)。
它可以 往后 跳恰好 b 个位置(即往左跳)。
它不能 连续 往后跳 2 次。
它不能跳到任何 forbidden 数组中的位置。
跳蚤可以往前跳 超过 它的家的位置,但是它 不能跳到负整数 的位置。
给你一个整数数组 forbidden ,其中 forbidden[i] 是跳蚤不能跳到的位置,同时给你整数 a, b 和 x ,请你返回跳蚤到家的最少跳跃次数。如果没有恰好到达 x 的可行方案,请你返回 -1 。
输入:forbidden = [14,4,18,1,15], a = 3, b = 15, x = 9
输出:3
解释:往前跳 3 次(0 -> 3 -> 6 -> 9),跳蚤就到家了。
输入:forbidden = [8,3,16,6,12,20], a = 15, b = 13, x = 11
输出:-1
输入:forbidden = [1,6,2,14,5,17,4], a = 16, b = 9, x = 7
输出:2
解释:往前跳一次(0 -> 16),然后往回跳一次(16 -> 7),跳蚤就到家了。
LeetCode 官方将本题难度定为中等。读完题目,本题求最短路径,哪就可以使用 BFS 了。
和标准 BFS 相比,本题有一个限制,那就是回跳不能连续两次。
如何解决这个问题呢?很简单,记录一下上次动作。这样我们就可以判断了。我们可以定义如下的数据类型。
struct JUMP {
int pos;//位置
bool act;//动作。false为向后跳,true向前跳
JUMP(int _pos, bool _act) : pos(_pos), act(_act) {}
JUMP() { pos=0; act=true; }
};
在如下的数据
[162,118,178,152,167,100,40,74,199,186,26,73,200,127,30,124,193,84,184,36,103,149,153,9,54,154,133,95,45,198,79,157,64,122,59,71,48,177,82,35,14,176,16,108,111,6,168,31,134,164,136,72,98]
29
98
80
卡了好久。原因是前后是不同的,一个点即可以是往前跳到的,也可以是往后跳到的。不能因为往前跳到了这个点,就不允许这个点以后不让往后跳到了。
我的控制方法是在向后不控制 visit。这里目前我也说不出一个所以然,再仔细查查资料。
也正是由于可以向后跳,使得我们需要控制向前跳的总次数。根据题目可知 x 的最大值是 2000,a 的最大值是 2000,因此 x+2a 是最大的位置,也就是 6000。操作了这个位置,肯定是到不了家的。
const int MAXN=6e3+4;
int cost[MAXN];
struct JUMP {
int pos;//位置
bool act;//动作。false为向后跳,true向前跳
JUMP(int _pos, bool _act) : pos(_pos), act(_act) {}
JUMP() { pos=0; act=true; }
};
class Solution {
public:
int minimumJumps(vector& forbidden, int a, int b, int x) {
if (0==x) {
return 0;
}
//可见性控制
vector visit(MAXN, false);
for (int i=0; i q;
q.push(JUMP(0, false));
visit[0]=true;
int cost=0;//价值
while (false==q.empty()) {
cost++;//下一跳价值
int len=q.size();
for (int i=0; i=0 && false==visit[npos] && false==curr.act) {
//合法性判断
if (x==npos) {
return cost;
}
//visit[npos]=true;
//加入队列
q.push(JUMP(npos, true));
}
}
}
return -1;
}
};
O(N)。
O(N)。