青训营AI刷题中档题 石子移动问题 解答 | 豆包MarsCode AI刷题

100 阅读4分钟

23、石子移动问题

问题背景

小S正在玩一个关于石子位置的游戏。石子位于一维数轴上的不同位置,用数组 stones 表示每颗石子的位置。游戏规则如下:

  1. 如果某颗石子位于最小或最大的位置,我们称其为端点石子。
  2. 在每个回合,小S可以将一颗端点石子移动到一个未占用的位置,使其不再是端点石子。
  3. 游戏的目标是通过移动石子,使所有石子的位置变得连续,且在无法进行任何移动操作时结束。

我们的任务是帮助小S计算可以移动的最大次数


问题分析

为了实现所有石子的位置连续,显然需要将最小位置和最大位置逐步调整到中间的空闲位置。
假设石子的位置为 stones=[x1,x2,…,xn]\text{stones} = [x_1, x_2, \ldots, x_n]stones=[x1​,x2​,…,xn​],要找到可以进行的最大移动次数,我们需要:

  1. 统计初始状态下石子的位置分布和间隙。
  2. 根据规则,反复移动端点石子到空闲位置,直至石子连续。

解题思路

通过以下步骤,可以高效地计算最大移动次数:

  1. 排序石子位置
    首先将石子的位置排序为递增数组 stones\text{stones}stones。这样,石子在数轴上的排列关系更加直观。

  2. 确定初始端点石子
    端点石子是位于最小和最大位置的石子,分别为数组的第一个元素 stones[0]\text{stones}[0]stones[0] 和最后一个元素 stones[−1]\text{stones}[-1]stones[−1]。

  3. 计算最大移动次数
    最大移动次数可以通过以下两种策略之一获得:

    • 移动最左侧的端点石子到右侧某个位置,或
    • 移动最右侧的端点石子到左侧某个位置。

    具体来说,最大移动次数公式为:

    max_moves=max(stones[n−1]−stones[1],stones[n−2]−stones[0])−(n−2)

    其中:

    • stones[n−1]−stones[1]\text{stones}[n-1] - \text{stones}[1]stones[n−1]−stones[1]:从最左侧开始移动,忽略第一个石子后剩余的间隙。
    • stones[n−2]−stones[0]\text{stones}[n-2] - \text{stones}[0]stones[n−2]−stones[0]:从最右侧开始移动,忽略最后一个石子后剩余的间隙。
    • n−2n-2n−2:中间的石子已经占据的位置数。
  4. 返回结果
    结果即为最大移动次数。


算法实现

以下是完整的 Python 实现:

def solution(stones):
if len(stones) == 1:
    return 0  # 如果只有一个石子,不需要移动

# 排序石子的位置
stones.sort()
n = len(stones)

# 计算最大移动次数
return max(stones[n - 1] - stones[1], stones[n - 2] - stones[0]) - (n - 2)


if __name__ == '__main__':
    print(solution([7, 4, 9]) == 2)  # 测试样例1
    print(solution([6, 5, 4, 3, 10]) == 3)  # 测试样例2
    print(solution([1, 2, 3, 4, 5]) == 0)  # 测试样例3

示例解析

以下是几个测试样例及其详细分析:

样例1:
输入:stones = [7, 4, 9]
排序后位置为 [4, 7, 9],间隙为 3 和 2。
最大移动次数为:

max⁡(9−7,7−4)−(3−2)=2\max(9 - 7, 7 - 4) - (3 - 2) = 2max(9−7,7−4)−(3−2)=2

输出:2。

样例2:
输入:stones = [6, 5, 4, 3, 10]
排序后位置为 [3, 4, 5, 6, 10],间隙为 1, 1, 1, 和 4。
最大移动次数为:

max⁡(10−4,6−3)−(5−2)=3\max(10 - 4, 6 - 3) - (5 - 2) = 3max(10−4,6−3)−(5−2)=3

输出:3。

样例3:
输入:stones = [1, 2, 3, 4, 5]
所有石子已连续,无需移动。
输出:0。


复杂度分析

  1. 时间复杂度:

    • 排序的时间复杂度为 O(nlog⁡n)O(n \log n)O(nlogn),这是最主要的计算部分。
    • 最大移动次数的计算为常数操作 O(1)O(1)O(1)。
      因此,整体时间复杂度为 O(nlog⁡n)O(n \log n)O(nlogn)。
  2. 空间复杂度:

    • 仅需要存储排序后的数组和几个中间变量,额外空间需求为 O(1)O(1)O(1)。
      整体空间复杂度为 O(1)O(1)O(1)。

总结

本问题的核心在于利用排序简化石子分布的计算,并通过数学公式快速评估最大移动次数。
通过排序确定端点石子的位置关系,使用公式 max⁡(stones[n−1]−stones[1],stones[n−2]−stones[0])−(n−2) 高效计算答案。该解法适用于任意长度的输入数据,复杂度合理且实现简洁。