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

104 阅读4分钟

import java.util.Arrays;

public class Main {

public static int solution(int[] stones) {
    if (stones.length == 1) {
        return 0;
    }
    Arrays.sort(stones);
    int n = stones.length;

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

    // 计算最小移动次数,使用滑动窗口
    int minMoves = Integer.MAX_VALUE;
    int j = 0;
    for (int i = 0; i < n; i++) {
        // 确保窗口内最多有 n 个石子
        while (j < n && stones[j] - stones[i] + 1 <= n) {
            j++;
        }
        // 如果窗口内有 n - 1 个石子,且空位为 1,则需要特殊处理
        int alreadyInPlace = j - i;
        if (alreadyInPlace == n - 1 && stones[j - 1] - stones[i] + 1 == n - 1) {
            minMoves = Math.min(minMoves, 2);
        } else {
            minMoves = Math.min(minMoves, n - alreadyInPlace);
        }
    }

    return maxMoves;
}

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

}

这个 Java 方法 solution 的作用是计算在给定的石子数组 stones 中,能够达到的最大和最小移动次数。以下是代码的关键部分及其解释:

  1. 判断石子数量:如果数组 stones 的长度为 1,返回 0,因为没有移动的必要。

  2. 排序:将石子数组进行排序,以方便后续计算。

  3. 计算最大移动次数

    • 最大移动次数通过比较两个情况得到:
      • 从最大石子到第二小石子的差值。
      • 从第二大石子到最小石子的差值。
    • 然后减去 n-2,这代表在最大分布中需要留出的空位。
  4. 计算最小移动次数

    • 初始化 minMoves 为最大整数值。
    • 使用滑动窗口方法,遍历石子数组,确保窗口内的石子数量不超过 n
    • 当窗口内有 n - 1 个石子且只缺一个位置时,特别处理,设置 minMoves 为 2。
    • 否则,更新 minMoves 为当前窗口外需要的移动次数。
  5. 返回最大移动次数:最终返回计算出的最大移动次数。

整体来说,该方法通过对输入数组进行排序和使用滑动窗口策略,计算出在对石子进行移动时的最大和最小移动次数。

这段代码的目的是计算将一组石子排列成序列所需的最大和最小移动次数。我们可以逐步分析这段代码的原理和功能。

代码逻辑分析

  1. 处理特殊情况

    • 如果传入的石子数组长度为1,表示只有一颗石子,因此不需要移动,直接返回0。
  2. 排序石子的位置

    • 使用 Arrays.sort(stones) 对石子的坐标进行排序,以便后续处理时简化距离计算。
  3. 计算最大移动次数(maxMoves)

    • 最大移动的计算涉及两个特定的位置:
      • stones[n - 1] - stones[1]:即从第二个石子移动到最后一个石子的距离。
      • stones[n - 2] - stones[0]:即从第一个石子移动到倒数第二个石子的距离。
    • 减去 (n - 2) 的原因是,最多移掉 n - 2 颗石子,从而使得剩下的两颗石子间的空位形成一次有效的移动。最终的最大移动次数由这两个值的较大者减去 (n - 2) 计算得出。
  4. 最小移动次数(minMoves)

    • 使用“滑动窗口”技术。i 标识了窗口的左边界,而 j 则是右边界,窗口内最多应包含 n 颗石子。
    • 内部的 while 循环保证了在 stones[i] 这一位置到 stones[j] 之间的距离加一不会超过 n
    • alreadyInPlace 计算在当前窗口中的石子数量。
    • 如果窗口包含 n - 1 颗石子,并且窗口范围正好覆盖了一些空位的情况,特别处理最小移动为2,表示可以通过移动两颗石子来填补空位。
    • 否则,正常计算出当前窗口中已有石子的数量,并更新最小移动次数为总石子数减去已有石子的数量。

返回值

  • 该代码最终返回最大移动次数 maxMoves。虽然计算了最小移动次数,但这部分并没有在返回值中体现。

总结

这段代码有效地计算了在给定的石子分布情况下重新排列需要的最大移动次数。虽然最小移动次数在逻辑中实现,但最终并未返回。如果需要完整功能,可能需要调整返回值部分以输出最小移动次数。