刷题笔记-最小步数移动 | 豆包MarsCodeAI刷题

72 阅读5分钟

最小步数移动

问题描述

小F正在进行一个 AB 实验,需要从整数位置 x 移动到整数位置 y。每一步可以将当前位置增加或减少,且每步的增加或减少的值必须是连续的整数(即每步的移动范围是上一步的 -1,+0 或 +1)。首末两步的步长必须是 1。我们的目标是求出从 xy 的最少步数。

image.png

输入描述

输入包含两个整数 xy,表示起始位置和目标位置。

输出描述

输出从 xy 所需的最小步数。

示例

  • 示例 1:

    • 输入:x_position = 12, y_position = 6
    • 输出:4
  • 示例 2:

    • 输入:x_position = 34, y_position = 45
    • 输出:6
  • 示例 3:

    • 输入:x_position = 50, y_position = 30
    • 输出:8

问题分析

为了求解从位置 x 到位置 y 的最小步数,我们首先需要明确移动的方式以及如何结合步长的变化来进行步数计算。下面详细展开步数计算的推导过程和规律发现。

1. 距离计算

首先,计算起始位置 x 和目标位置 y 的绝对距离:

x = abs(xPosition - yPosition)

这个距离 x 表示我们需要移动的总距离,即要跨越的间隔。

2. 步长累加

接下来,我们需要引入步长的概念。根据题意,首尾两步的步长必须是 1,而后续的步长会根据前一步的步长变化。在每一步中,当前步长可以是前一步的 -1、0 或 +1。

初步探索

我们从初始步长 1 开始,随着每一步的增加,步长将逐渐增加:

  • 第一步的步长为 1,对应的移动是 ±1
  • 第二步的步长为 2,移动范围是 13(即 ±2)。
  • 第三步的步长为 3,移动范围是 25(即 ±3)。

以此类推,第 cnt 步的步长为 cnt,因此从位置 x 到达目标位置 y 时的累积步长和为:

  • 1 步的步长为 1
  • 2 步的步长为 2
  • 3 步的步长为 3
  • ...
  • cnt 步的步长为 cnt

总的移动范围为: Total Movement=1+2+3+…+cnt=cnt×(cnt+1)/2

3. 确定步数的临界条件

为了逐步逼近目标距离 x,我们需要确保步长累加的总和大于或等于目标距离。我们将这一条件反复应用于循环中:

while x > 2 * cnt:
    x -= 2 * cnt
    cnt += 1

这里的条件 x > 2 * cnt 是关键:

  • x 大于 2 * cnt 时,意味着当前步长累加的总和还不足以覆盖需要移动的距离。此时我们就需要继续增加步数 cnt,并更新剩余的距离 x

4. 剩余距离的分类处理

经过循环后,剩余的距离 x 会落入以下几种情况中:

  1. 完全到达目标 (x == 0):

    • 这意味着我们正好用累加的步长到达了目标,返回的步数为 cnt * 2 - 2。这里的 -2 是因为首尾两步的步长为 1
  2. 剩余距离小于当前步长 (0 < x <= cnt):

    • 如果剩余距离 x1cnt 之间,意味着我们可以在最后一步用更小的步长到达目标位置。此时返回 cnt * 2 - 1,因为最后一步的步长也是 1,而首尾两步分别贡献了 11,但最后一步用 1 的步长替代了当前步长。
  3. 剩余距离恰好在当前步长和其两倍之间 (cnt <= x <= 2 * cnt):

    • 如果剩余距离 x 在当前步长的范围内,可以通过前一步的调整来到达目标,返回 cnt * 2,表示我们可以继续使用当前步长到达目标。

5. 规律总结

通过以上分析,我们发现以下规律:

  • 步长是动态变化的并且是连续的。
  • 通过不断调整步长,我们可以适应不同的剩余距离,并通过分类讨论确定最终的步数。
  • 关键在于累加步长对目标距离的覆盖情况,根据剩余距离的不同情况进行相应的处理。

代码实现

结合上述发现,我们可以将这个过程编写为代码:

def solution(xPosition, yPosition):
    x = abs(xPosition - yPosition)  # 计算距离
    cnt = 1  # 初始化步数

    # 逐步增加步长,直到步长累加的总和达到或超过目标距离
    while x > 2 * cnt:
        x -= 2 * cnt
        cnt += 1

    # 根据剩余距离的不同情况,计算最终的步数
    if x == 0:
        return cnt * 2 - 2
    if x > 0 and x <= cnt:
        return cnt * 2 - 1
    if x >= cnt and x <= 2 * cnt:
        return cnt * 2

    return 0

代码解读

  1. 距离计算

    • 使用 abs 函数来计算 xy 之间的绝对距离。
  2. 步长累加

    • 初始化 cnt 为 1,表示当前的步长。
    • 使用 while 循环,逐步增加 cnt,同时减少剩余的距离 x,直到 x 小于或等于 2 * cnt
  3. 步数计算

    • 根据剩余的距离 x,判断最终步数:
      • 如果 x 为 0,说明正好到达目标,返回 cnt * 2 - 2
      • 如果 x 在 1 到 cnt 之间,返回 cnt * 2 - 1
      • 如果 xcnt2 * cnt 之间,返回 cnt * 2

关键点总结

  • 连续步长:每一步的步长是动态变化的,这使得问题变得复杂,但同时也为我们提供了利用规律减少计算的可能。
  • 边界条件:明确了首尾步长必须为 1,以及在特定条件下(如剩余距离为 0)如何返回结果。
  • 效率提升:通过逐步增加步长的方式,能够有效避免不必要的计算,提高效率。

知识联想

  1. 动态规划:虽然本题可以通过循环和条件判断解决,但在更复杂的变种问题中,可能需要考虑使用动态规划来存储状态,避免重复计算。
  2. 路径问题:类似于路径问题,这里我们可以将其看作是一个状态转移的过程,动态调整前一步的结果来计算到达目的地所需的步数。
  3. 图论与最短路径:可以将这个问题与图论中的最短路径问题相类比,尽管我们是在一维空间中进行移动,但相似的思想在多维移动中也适用。