计算从位置 x 到 y 的最少步数
问题描述
小F正在进行一个 AB 实验,需要从整数位置 x
移动到整数位置 y
。每一步可以将当前位置增加或减少,且每步的增加或减少的值必须是连续的整数(即每步的移动范围是上一步的 -1
,+0
或 +1
)。首末两步的步长必须是 1
。求从 x
到 y
的最少步数。
输入描述
输入包含两个整数 x
和 y
,表示起始位置和目标位置。
输出描述
输出从 x
到 y
所需的最小步数。
测试样例
样例1:
输入:
x_position = 12, y_position = 6
输出:
4
样例2:
输入:
x_position = 34, y_position = 45
输出:
6
样例3:
输入:
x_position = 50, y_position = 30
输出:
8
样例4:
输入:
x_position = 0, y_position = 0
输出:
0
思路
首先处理特殊情况,x和y距离如果是0或1,直接返回
然后模拟情况,如下(orz
距离 | 步数变化 | 最小步数 |
---|---|---|
0 | 0 | 0 |
1 | 1 | 1 |
2 | 1 1 | 2 |
3 | 1 1 1 | 3 |
4 | 1 2 1 | 3 |
5 | 1 2 1 1 | 4 |
6 | 1 2 2 1 | 4 |
7 | 1 2 2 1 1 | 5 |
8 | 1 2 2 2 1 | 5 |
9 | 1 2 3 2 1 | 5 |
10 | 1 2 3 2 1 1 | 6 |
... | ... | ... |
13 | 1 2 3 3 2 1 1 | 7 |
... | ... | ... |
20 | 1 2 3 4 4 3 2 1 | 8 |
暴力
根据规律,其实就是一个等差数列, <math xmlns="http://www.w3.org/1998/Math/MathML"> S n = n a 1 + n ( n − 1 ) d 2 S_n=na_1+\frac{n(n-1)d}{2} </math>Sn=na1+2n(n−1)d,所以可以先遍历求出步长最大值a,对于最大步长的预设值,假设刚好是一个回文的字符串,那么最大步长范围为 <math xmlns="http://www.w3.org/1998/Math/MathML"> a ≈ ( a + 1 ) a 2 ∗ 2 ≈ 步长和 a \approx \sqrt{\frac{(a+1)a}{2}*2}\approx \sqrt{步长和} </math>a≈2(a+1)a∗2 ≈步长和 ,然后对剩余步数来进行遍历
- 按规律等差数列求和左右两边已走步数 <math xmlns="http://www.w3.org/1998/Math/MathML"> a + a ( a − 1 ) 2 = a 2 + a 2 = a ( a + 1 ) 2 ⇒ a ( a + 1 ) 2 + a ( a − 1 ) 2 a+\frac{a(a-1)}{2} = \frac{a^2+a}{2}=\frac{a(a + 1)}{2}\Rightarrow \frac{a(a+1)}{2}+\frac{a(a-1)}{2} </math>a+2a(a−1)=2a2+a=2a(a+1)⇒2a(a+1)+2a(a−1)
- 剩余步数: <math xmlns="http://www.w3.org/1998/Math/MathML"> r e s = d i s t − c n t res = dist-cnt </math>res=dist−cnt,这是就只要考虑剩下步数是直接用最大的步长还是用1来填充
简化
因为这个问题是求出最小步数,可以把问题简化为
- 对于能够用等差数列求和的,步数为 <math xmlns="http://www.w3.org/1998/Math/MathML"> a + ( a − 1 ) = 2 a + 1 a + (a - 1)=2a+1 </math>a+(a−1)=2a+1
- 根据上面讲述的a和步长和的关系,可以求出剩余步数为 <math xmlns="http://www.w3.org/1998/Math/MathML"> d i s t − a ∗ a dist-a*a </math>dist−a∗a,然后就要考虑补充1还是补充a
-
补充a
说明此时剩余步数是a的倍数,补充a的步数为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 剩余步数 a \frac{剩余步数}{a} </math>a剩余步数
-
补充1
补充1不补充a说明a不能整除剩余步数,所以此时看余数就是补充1的步数数量
-
python
def solution(x_position, y_position):
dist = abs(x_position - y_position)
if dist == 0:
return 0
elif dist == 1:
return 1
a = math.isqrt(dist)
cnt = (dist - a * a) // a
if (dist - a * a) % a:
cnt += 1
return cnt + 2 * a - 1
对步长递增取值和递减取值的思考
根据题目要求每步的移动范围是上一步的 -1
,+0
或 +1
和 首末两步的步长必须是 1
。求从 x
到 y
的最少步数这两个条件进行模拟,可以看出需要使用等差数列来作为解题的核心。
条件:最小步数 <math xmlns="http://www.w3.org/1998/Math/MathML"> → \rightarrow </math>→步长尽可能的大,所以在移动范围的限制下,递增可以最快的将步数达到需求,同时考虑到最后一步为1,那么最后一步和递增最大点之间应该是0
或者-1
的关系,可以将0
的插入思考全部放在递减部分,那么0怎么插入递减的步数中?选择范围为最大步长到1,如果不使用最大步长a,那么可能剩余的数为 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ 1 , a − 1 ] [1,a-1] </math>[1,a−1]之间,这时候0可以插入中间满足要求的数,使取值在 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ 1 , a − 1 ] [1,a-1] </math>[1,a−1]的这个数值加上后总步数为x和y的距离