23、石子移动问题
问题背景
小S正在玩一个关于石子位置的游戏。石子位于一维数轴上的不同位置,用数组 stones 表示每颗石子的位置。游戏规则如下:
- 如果某颗石子位于最小或最大的位置,我们称其为端点石子。
- 在每个回合,小S可以将一颗端点石子移动到一个未占用的位置,使其不再是端点石子。
- 游戏的目标是通过移动石子,使所有石子的位置变得连续,且在无法进行任何移动操作时结束。
我们的任务是帮助小S计算可以移动的最大次数。
问题分析
为了实现所有石子的位置连续,显然需要将最小位置和最大位置逐步调整到中间的空闲位置。
假设石子的位置为 stones=[x1,x2,…,xn]\text{stones} = [x_1, x_2, \ldots, x_n]stones=[x1,x2,…,xn],要找到可以进行的最大移动次数,我们需要:
- 统计初始状态下石子的位置分布和间隙。
- 根据规则,反复移动端点石子到空闲位置,直至石子连续。
解题思路
通过以下步骤,可以高效地计算最大移动次数:
-
排序石子位置
首先将石子的位置排序为递增数组 stones\text{stones}stones。这样,石子在数轴上的排列关系更加直观。 -
确定初始端点石子
端点石子是位于最小和最大位置的石子,分别为数组的第一个元素 stones[0]\text{stones}[0]stones[0] 和最后一个元素 stones[−1]\text{stones}[-1]stones[−1]。 -
计算最大移动次数
最大移动次数可以通过以下两种策略之一获得:- 移动最左侧的端点石子到右侧某个位置,或
- 移动最右侧的端点石子到左侧某个位置。
具体来说,最大移动次数公式为:
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:中间的石子已经占据的位置数。
-
返回结果
结果即为最大移动次数。
算法实现
以下是完整的 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。
复杂度分析
-
时间复杂度:
- 排序的时间复杂度为 O(nlogn)O(n \log n)O(nlogn),这是最主要的计算部分。
- 最大移动次数的计算为常数操作 O(1)O(1)O(1)。
因此,整体时间复杂度为 O(nlogn)O(n \log n)O(nlogn)。
-
空间复杂度:
- 仅需要存储排序后的数组和几个中间变量,额外空间需求为 O(1)O(1)O(1)。
整体空间复杂度为 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) 高效计算答案。该解法适用于任意长度的输入数据,复杂度合理且实现简洁。