使用 Python 解题 - 石子移动问题

80 阅读3分钟

一,题目详情

1,问题描述

小S正在玩一个关于石子的游戏,给定了一些石子,它们位于一维数轴的不同位置,位置用数组 stones 表示。如果某个石子处于最小或最大的一个位置,我们称其为端点石子。

在每个回合,小S可以将一颗端点石子移动到一个未占用的位置,使其不再是端点石子。游戏继续,直到石子的位置变得连续,无法再进行任何移动操作。

你需要帮助小S找到可以移动的最大次数。

2,测试样例

样例1:

输入:stones = [7, 4, 9]

输出:2

样例2:

输入:stones = [6, 5, 4, 3, 10]

输出:3

样例3:

输入:stones = [1, 2, 3, 4, 5]

输出:0

85a2866e0b758e30a41f613900df15f.png

二,解题思路

1,问题分析

我们需要找到石子可以移动的最大次数。每次移动只能移动端点石子到一个未占用的位置,使其不再是端点。游戏结束的条件是石子的位置连续。

2,算法策略

核心思想是:计算所有石子之间的间隔总和,然后减去最小的端点间隔(左端点间隔或右端点间隔),因为最终游戏结束时,端点间隔中较小的那个将被保留,而较大的那个会被消除。

具体步骤如下:

  1. 对石子位置进行排序。
  2. 计算所有相邻石子之间的间隔总和。
  3. 计算左端点间隔(第二个石子与第一个石子的间隔)和右端点间隔(最后一个石子与倒数第二个石子的间隔)。
  4. 最大移动次数为总间隔减去左端点间隔和右端点间隔中的较小值。

3,逐步推演(以样例1为例)

输入:stones = [7, 4, 9]

排序后:[4, 7, 9]

相邻间隔: 7 - 4 - 1 = 2 9 - 7 - 1 = 1 总间隔:2 + 1 = 3

左端点间隔:7 - 4 - 1 = 2 右端点间隔:9 - 7 - 1 = 1

最小端点间隔为1,所以最大移动次数为3 - 1 = 2。

三,代码实现

def solution(stones: list) -> int:
    stones.sort()
    n = len(stones)
    if n <= 1:
        return 0
    sum_gaps = 0
    for i in range(n - 1):
        sum_gaps += stones[i + 1] - stones[i] - 1
    left_gap = stones[1] - stones[0] - 1
    right_gap = stones[-1] - stones[-2] - 1
    return sum_gaps - min(left_gap, right_gap)

1,复杂度分析

  • 时间复杂度:O(n log n)

    • 主要为排序的时间复杂度
  • 空间复杂度:O(1)

    • 仅使用常数级额外空间

2,边界测试

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

    # 边界测试:只有一个石子
    print(solution(stones=[5]) == 0)

    # 边界测试:两个石子
    print(solution(stones=[1, 5]) == 3)

四,总结

通过计算所有间隔并减去最小的端点间隔,我们实现了:

  1. 找到最大移动次数:通过分析石子的间隔分布
  2. 高效的计算:利用排序和简单遍历
  3. 普适性:适用于所有石子分布情况

这种解法不仅高效,还易于理解和实现。当遇到“需要计算石子移动的最大次数”类问题时,分析间隔和端点特性往往是解决问题的关键策略。

6748047b522ec4ca68f831d18deabb5.png