39. 计算位置 x 到 y 的最少步数
问题描述
给定两个位置 x
和 y
,从位置 x
到 y
,每一步只能向前走或者向后走,且每一步的步长必须是一个正整数。要求计算从 x
到 y
的最少步数。
思路解析
题目要求第一步必须是 1,并且最后一步也必须是 1。这给我们的解题思路提供了线索:最优的步数安排一定是一个“先上坡再下坡”的过程。
-
上坡和下坡的规律:
- 在上下坡的过程中,步长一般是递增的,也就是说从
1
开始,步长逐渐增大,直到某个峰值后开始逐渐减少,直到最后再回到1
。 - 最优的解通常要求步数达到峰值后,再按照一个最小的步长(即
1
)返回。
- 在上下坡的过程中,步长一般是递增的,也就是说从
-
最优方案:
- 最理想的情况是可以完美地上下坡,不需要中途补充额外的步数。
- 如果不能完美下坡,就可以通过增加一次适当的步长来弥补差距。特别是当坡顶的步长不够精确地匹配目标位置时,我们可以通过多走一步来补齐剩余的距离。
-
如何优化计算:
- 我们将通过枚举不同的峰值来寻找最小步数。每一个峰值的选择都决定了上坡和下坡的速度。
- 计算每个峰值下,所能走的最大距离,再根据剩余距离来调整。
解题步骤
-
计算距离: 首先,我们需要计算从
x
到y
的距离dis
,即dis = abs(x_position - y_position)
。 -
枚举峰值: 我们通过一个循环枚举不同的步数峰值
peak
。每个peak
对应一个步长序列,步长从1
增加到peak
,再从peak
减少到1
。- 对于每个峰值
peak
,我们首先计算上坡的最大步数(即峰值所对应的距离):
- 然后计算剩余的距离
diff = dis - distance_covered
。
- 对于每个峰值
-
判断和调整步数:
- 如果剩余的距离
diff
小于0
,说明当前的峰值过大,不可能再增大步长了,返回当前的步数。 - 如果
diff
大于 0,那么需要补充更多的步数。故计算diff / peak
来进行判断,如果还有剩余距离,最终需要多走一步。
- 如果剩余的距离
-
更新最小步数: 每次计算完一个峰值对应的步数后,我们都会更新最小步数
result
。
复杂度分析
- 时间复杂度:
O(dis)
。枚举峰值的循环次数大约为dis
,因此时间复杂度是O(dis)
。 - 空间复杂度:
O(1)
。整个过程中使用的额外空间是固定的,不依赖于输入规模。
Code
import math;
def solution(x_position, y_position):
dis = abs(x_position - y_position) # 计算 x 到 y 的距离
step_count = 0
result = 2e9
for peak in range(1, dis): # 枚举步数峰值
# 等差数列求和:首项为 1, 末项为峰值
# S = peak(1+peak)/2
# 2S-peak 为走的步数, 即 peak*peak
# peak*2-1 为走的次数
diff = dis - peak*peak
if(diff < 0): # 如果已经走超了,就代表不可能存在更大的峰值
return step_count
step_count = peak*2 - 1
# 按峰值快步前进
step_count += int(diff / peak) # 记得强制类型转换,下取整
diff %= peak
if(diff != 0):
# 如果步数不够。则需要补充一步补齐
step_count += 1
result = min(step_count, result) # 更新最小步数
return step_count
if __name__ == "__main__":
# You can add more test cases here
print(solution(12, 6) == 4)
print(solution(34, 45) == 6)
print(solution(50, 30) == 8)