青训营刷题-2

835 阅读4分钟

2 计算位置x到y的最少步数

AB 实验同学每天都很苦恼如何可以更好地进行 AB 实验,每一步的流程很重要,我们目标为了缩短所需的步数。

我们假设每一步对应到每一个位置。从一个整数位置 x 走到另外一个整数位置 y,每一步的长度是正整数,每步的值等于上一步的值 -1+0+1。求 xy 最少走几步。并且第一步必须是 1,最后一步必须是 1,从 xy 最少需要多少步。

样例说明

  • 整数位置 x12,另外一个整数位置 y6,我们需要从 x 走到 y,最小的步数为:1221,所以我们需要走 4 步。
  • 整数位置 x34,另外一个整数位置 y45,我们需要从 x 走到 y,最小的步数为:123221,所以我们需要走 6 步。
  • 整数位置 x50,另外一个整数位置 y30,我们需要从 x 走到 y,最小的步数为:12344321,所以我们需要走 8 步。

输入格式

输入包含 2 个整数 xy。(0<=x<=y<2^31

输出格式

对于每一组数据,输出一行,仅包含一个整数,从 xy 所需最小步数。

输入样例

12 6
34 45
50 30

输出样例

4
6
8

解题思路

要解决这个问题,我们需要理解步长变化的规则,并设计一种策略,既能快速覆盖距离,又能满足步长变化的限制。以下是详细的思路分析:

1. 距离计算

首先,计算总距离D = |y - x|。不论是向左走还是向右走,步长的选择和步数的计算方式都是类似的。

2. 步长变化规则

  • 起始步长:第一步必须是1
    • 步长变化:每一步的步长可以是前一步步长的-10+1
    • 结束步长:最后一步必须是1

3. 步长序列的特性

为了最小化步数,我们希望步长尽可能地快速增加,以覆盖更多的距离,然后再逐步减少步长,以满足最后一步必须为1的条件。这类似于形成一个“山峰”形状的步长序列。

4. 最大步长k的确定

假设步长序列的最大步长为k,那么序列大致会是1, 2, 3, ..., k, ..., 3, 2, 1。需要确定k的值,使得步长序列的总和尽可能接近但不超过D
为了估算k,我们可以利用数学中的等差数列求和公式:

S= 1 + 2 + 3 + ··· + k = k(k + 1)/2

这个公式表示步长从1增加到k时的总距离。如果我们希望总距离接近D,则可以近似认为: k^2 == D, 因此,k的值可以通过计算k = floor(√D)来估算。

5. 计算最少步数

根据最大步长k,最少步数可以通过以下公式计算:

  • 如果k^2 < D
    这里的情况是
    1 + 2 + 3 + ··· + k + k-1 + k-2 + ··· + 2 + 1 < D

    1 + 2 + 3 + ··· + k + k+1 + k + k-1 + ··· + 2 + 1 > D
    范围是 1 到 2k,对应 1 到 2 个数,这些数可以是 1 到 k 中的任意数,只要满足最后的序列相加等于 D。
    • 需要额外的步数来覆盖剩余的距离D - k^2
    • 额外步数extraSteps = ceil((D - k^2) / k)
    • 总步数n = 2k - 1 + extraSteps
  • 否则
    • 总步数n = 2k - 1

6. 特殊情况处理

  • D = 0:起点和终点相同,不需要任何步数,n = 0

算法实现


public class Main {
    public static int solution(int xPosition, int yPosition) {
        int diff = Math.abs(xPosition - yPosition);
        if (diff == 0) {
            return 0;
        }
        // 计算可能的k   
        int k = (int)Math.floor(Math.sqrt(diff));
        // (k+1)*k/2   +  k*(k-1)/2  = k * k 
        // 1 2 + 1     1 2 3 + 2 1  
        // 1 2 3 4 + 3 2 1
        // 更小   
        long kSquared = (long)k * k;
        if (kSquared < diff) {
            // 这个差值 小于 1 到 k
            long remaining = diff - kSquared;
            // Ceiling division: (a + b -1) / b
            long extraSteps = (remaining + k -1) / k;
            return 2 * k -1 + (int)extraSteps;
        } else {
            return 2 * k -1;
        }
    }

    public static void main(String[] args) {
        // You can add more test cases here
        System.out.println(solution(12, 6) == 4);
        System.out.println(solution(34, 45) == 6);
        System.out.println(solution(50, 30) == 8);
    }
}