2 计算位置x到y的最少步数
AB 实验同学每天都很苦恼如何可以更好地进行 AB 实验,每一步的流程很重要,我们目标为了缩短所需的步数。
我们假设每一步对应到每一个位置。从一个整数位置 x 走到另外一个整数位置 y,每一步的长度是正整数,每步的值等于上一步的值 -1, +0,+1。求 x 到 y 最少走几步。并且第一步必须是 1,最后一步必须是 1,从 x 到 y 最少需要多少步。
样例说明
- 整数位置
x为12,另外一个整数位置y为6,我们需要从x走到y,最小的步数为:1,2,2,1,所以我们需要走4步。 - 整数位置
x为34,另外一个整数位置y为45,我们需要从x走到y,最小的步数为:1,2,3,2,2,1,所以我们需要走6步。 - 整数位置
x为50,另外一个整数位置y为30,我们需要从x走到y,最小的步数为:1,2,3,4,4,3,2,1,所以我们需要走8步。
输入格式
输入包含 2 个整数 x,y。(0<=x<=y<2^31)
输出格式
对于每一组数据,输出一行,仅包含一个整数,从 x 到 y 所需最小步数。
输入样例
12 6
34 45
50 30
输出样例
4
6
8
解题思路
要解决这个问题,我们需要理解步长变化的规则,并设计一种策略,既能快速覆盖距离,又能满足步长变化的限制。以下是详细的思路分析:
1. 距离计算
首先,计算总距离D = |y - x|。不论是向左走还是向右走,步长的选择和步数的计算方式都是类似的。
2. 步长变化规则
- 起始步长:第一步必须是
1 -
- 步长变化:每一步的步长可以是前一步步长的
-1、0或+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);
}
}