石子移动问题|豆包MarsCode AI刷题

58 阅读3分钟

要解析这个问题,我们首先要理解几个关键点:

  1. 初始状态:石子位于一维数轴的不同位置,位置由数组 stones 表示。
  2. 端点石子:位于数轴最小或最大位置的石子。
  3. 移动规则:每个回合可以将一个端点石子移动到一个未占用的位置。
  4. 游戏结束条件:石子的位置变得连续,即任意两个相邻石子的位置差为1。

我们的目标是找到可以移动的最大次数。

解题思路

  1. 排序:首先,对石子位置进行排序,这样我们可以方便地处理端点石子。

  2. 计算空隙:排序后,计算相邻石子之间的空隙(即位置差)。

  3. 模拟移动

    • 每次选择一个端点石子(最小或最大位置的石子)。
    • 尝试将其移动到相邻的未占用位置(即填补一个空隙)。
    • 更新石子位置和空隙。
  4. 统计移动次数:记录每次成功的移动,直到所有石子位置连续。

然而,直接模拟移动可能非常复杂且效率低下,因为我们需要考虑所有可能的移动顺序和结果。幸运的是,这个问题有一个更简洁的解法。

简洁解法

由于最终目标是使所有石子位置连续,我们可以观察到:

  • 移动端点石子实际上是在填补空隙。
  • 移动的最大次数等于初始状态下所有空隙的总和(因为每个空隙都需要被填补一次)。
  • 但是,由于移动是连续的,并且最终所有石子都要紧密相连,因此一些移动可能会“抵消”掉(例如,将一个石子从一端移动到中间,然后另一个石子从另一端移动到刚才空出的位置)。

为了找到可以移动的最大次数,我们可以这样做:

  1. 对石子位置进行排序。
  2. 计算相邻石子之间的空隙。
  3. 由于最终石子会紧密相连,我们可以假设它们最终形成一个连续的区间 [start, start + n - 1],其中 n 是石子的数量。
  4. 计算当前石子位置到这个连续区间的“偏移量”,这个偏移量实际上就是需要移动的次数(因为每个偏移都对应一个空隙需要填补)。

实现步骤

  1. 排序石子位置数组 stones
  2. 计算目标连续区间的起始位置 start,这可以通过 (最小位置 + 最大位置 - n + 1) // 2 来计算(这里 n 是石子的数量)。
  3. 遍历排序后的石子位置,计算每个位置到目标连续区间的偏移量,并累加这些偏移量的绝对值(因为偏移需要被填补)。

代码实现

在这个实现中,我们首先对石子位置进行排序,然后计算目标连续区间的起始位置 target_start。接着,我们遍历每个石子位置,计算它到目标位置的偏移量,并累加这些偏移量的绝对值作为移动次数。

注意:这个解法是基于观察得出的,它假设了最终石子会形成一个连续的区间,并且所有空隙都需要被填补一次。由于移动是连续的,并且最终状态是唯一的(所有石子紧密相连)