1654. Minimum Jumps to Reach Home

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值