A certain bug’s home is on the x-axis at position x. Help them get there from position 0.
The bug jumps according to the following rules:
It can jump exactly a positions forward (to the right).
It can jump exactly b positions backward (to the left).
It cannot jump backward twice in a row.
It cannot jump to any forbidden positions.
The bug may jump forward beyond its home, but it cannot jump to positions numbered with negative integers.
Given an array of integers forbidden, where forbidden[i] means that the bug cannot jump to the position forbidden[i], and integers a, b, and x, return the minimum number of jumps needed for the bug to reach its home. If there is no possible sequence of jumps that lands the bug on position x, return -1.
Example 1:
Input: forbidden = [14,4,18,1,15], a = 3, b = 15, x = 9
Output: 3
Explanation: 3 jumps forward (0 -> 3 -> 6 -> 9) will get the bug home.
Example 2:
Input: forbidden = [8,3,16,6,12,20], a = 15, b = 13, x = 11
Output: -1
Example 3:
Input: forbidden = [1,6,2,14,5,17,4], a = 16, b = 9, x = 7
Output: 2
Explanation: One jump forward (0 -> 16) then one jump backward (16 -> 7) will get the bug home.
Constraints:
- 1 <= forbidden.length <= 1000
- 1 <= a, b, forbidden[i] <= 2000
- 0 <= x <= 2000
- All the elements in forbidden are distinct.
- Position x is not forbidden.
盯着人家的答案看了一上午, 基本看明白了
- 能到达的点必定是 n * gcd(a, b), 这个楼主说是根据 Bezout’s Identity 得来的
- 关于检查上限, 假设出发点为 p0, 往前走一步为 p0 + a, 但是在[p0, p0+a]这个区间里还有若干个点是可以到达的[p0 + gcd(a, b), p0 + 2 * gcd(a, b), …, p0 + a - gcd(a, b)], 这些点是从后面的点退一步 b 的距离到达的, 后面的那些点是[p0 + gcd(a, b) + b, p0 + 2 * gcd(a, b) + b, … , p0 + a - gcd(a, b) + b], 所以我们要检查 p0 能否到达,只需要检测到 p0 + a - gcd(a, b) + b 这个点就可以了, 这个当时看答案看了好久
- 关于为什么要取 max(x, max(forbidden))来做 p0, 这个目前还没理解
use std::collections::HashSet;
impl Solution {
fn gcd(a: i32, b: i32) -> i32 {
if b == 0 {
return a;
}
let c = a % b;
Solution::gcd(b, c)
}
pub fn minimum_jumps(forbidden: Vec<i32>, a: i32, b: i32, x: i32) -> i32 {
let gcd = Solution::gcd(a, b);
if x % gcd != 0 {
return -1;
}
let forbidden: HashSet<i32> = forbidden.into_iter().collect();
let boundary = x.max(*forbidden.iter().max().unwrap()) + a + b;
let mut stack = vec![(0, -1)];
let mut visited: HashSet<(i32, i32)> = vec![(0, -1)].into_iter().collect();
let mut steps = 0;
loop {
let mut new_stack = Vec::new();
for (v, dir) in stack {
if v == x {
return steps;
}
if v + a <= boundary
&& !forbidden.contains(&(v + a))
&& !visited.contains(&(v + a, 1))
{
visited.insert((v + a, 1));
new_stack.push((v + a, 1));
}
if dir != -1
&& v - b > 0
&& !forbidden.contains(&(v - b))
&& !visited.contains(&(v - b, -1))
{
visited.insert((v - b, -1));
new_stack.push((v - b, -1));
}
}
if new_stack.is_empty() {
return -1;
}
steps += 1;
stack = new_stack;
}
}
}

该博客讨论了一种基于欧几里得算法(Bezout's Identity)解决虫子跳跃问题的方法。给定虫子的起始位置、前进和后退跳跃步长以及禁止跳跃的位置数组,目标是找到虫子到达指定家位置所需的最小跳跃次数。通过计算最大可达范围并使用深度优先搜索,可以确定是否能够到达家并计算跳跃次数。如果无法到达,则返回-1。博客中还提到,能够到达的点遵循n*gcd(a,b)的规律,并提供了具体实现代码。
521

被折叠的 条评论
为什么被折叠?



