青训营X豆包MarsCode 技术训练营 刷题 石子移动问题 | 豆包MarsCode AI 刷题

29 阅读3分钟

问题理解

这个问题可以看作是一个关于石子移动的策略游戏。给定一组石子的位置,我们需要计算出在石子位置变得连续之前,可以进行的最大移动次数。每次移动只能将一个端点石子(即位置最小或最大的石子)移动到一个未占用的位置,使其不再是端点石子。

数据结构选择

由于我们需要对石子的位置进行排序和比较,数组是一个合适的数据结构。通过排序,我们可以更容易地找到端点石子,并计算出它们之间的空位。

算法步骤

  1. 排序:首先对石子的位置进行排序。排序后,我们可以更容易地找到端点石子,并计算出它们之间的空位。
  2. 计算最大移动次数:最大移动次数可以通过计算排序后相邻石子之间的空位来得到。具体来说,对于每一对相邻的石子 stones[i]stones[i-1],它们之间的空位数为 stones[i] - stones[i-1] - 1。将所有这些空位数相加,就可以得到最大移动次数。
  3. 计算最小移动次数:最小移动次数可以通过考虑端点石子的移动来计算。具体来说,我们需要考虑将最左边的石子移动到下一个位置,或者将最右边的石子移动到前一个位置。这两种情况中,移动次数较小的那个就是最小移动次数。
  4. 计算最终结果:最终结果是最大移动次数减去最小移动次数。这个结果表示在石子位置变得连续之前,可以进行的最大移动次数。

具体实现思路

  1. 排序:使用 Arrays.sort(stones) 对石子位置进行排序。
  2. 计算最大移动次数:遍历排序后的数组,计算相邻石子之间的空位数,并累加得到最大移动次数。
  3. 计算最小移动次数:比较最左边和最右边石子的移动次数,取较小的那个作为最小移动次数。
  4. 返回结果:最大移动次数减去最小移动次数,得到最终结果。

复杂度分析

  • 时间复杂度:排序的时间复杂度为 O(n log n),计算最大和最小移动次数的时间复杂度为 O(n)。因此,总的时间复杂度为 O(n log n)
  • 空间复杂度:除了输入数组外,我们只使用了常数级别的额外空间,因此空间复杂度为 O(1)
import java.util.Arrays;

public class Main {
    public static int solution(int[] stones) {
        // 首先对石子位置进行排序
        Arrays.sort(stones);

        int n = stones.length;
        int maxMoves = 0;

        // 计算最大移动次数
        for (int i = 1; i < n; i++) {
            maxMoves += stones[i] - stones[i - 1] - 1;
        }

        // 计算最小移动次数
        int minMoves = Math.min(stones[1] - stones[0], stones[n - 1] - stones[n - 2]) - 1;

        return maxMoves - minMoves;
    }

    public static void main(String[] args) {
        System.out.println(solution(new int[]{7, 4, 9}) == 2); // true
        System.out.println(solution(new int[]{6, 5, 4, 3, 10}) == 3); // true
        System.out.println(solution(new int[]{1, 2, 3, 4, 5}) == 0); // true
    }
}

总结

通过排序和简单的数学计算,我们可以有效地解决这个问题。关键在于理解如何计算最大和最小移动次数,并通过它们来得到最终的结果。这个问题的核心在于如何合理地移动端点石子,使其位置变得连续,同时最大化移动次数。通过上述步骤,我们可以确保在石子位置变得连续之前,进行尽可能多的移动操作。