端点石子移动问题

问题描述

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

在每个回合,小S可以将一颗端点石子移动到一个未占用的位置,使其不再是端点石子。值得注意的是,如果石子的位置是连续的,则游戏结束,因为没有可以进行的移动操作。

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


测试样例

样例1:

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

输出:1

样例2:

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

输出:2

样例3:

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

输出:0

Java代码

ini 复制代码
 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;
    // 特殊处理 n = 2 的情况
    if (n == 2) {
        if (stones[1] - stones[0] == 1) {
            return 0; // 相邻则不需要移动
        }
        return 2; // 不相邻则需要移动两次
    }

    // 计算最大移动次数
    int maxMoves = stones[n - 1] - stones[0] + 1 - n;

    // 计算最小移动次数,使用滑动窗口
    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 Math.min(minMoves, maxMoves);
}

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

时间复杂度分析

  1. 排序操作

    • Arrays.sort(stones); 使用的是快速排序,时间复杂度为 O(n log n)
  2. 特殊处理 n = 2 的情况

    • 这部分是常数时间操作,时间复杂度为 O(1)
  3. 计算最大移动次数

    • int maxMoves = stones[n - 1] - stones[0] + 1 - n; 是常数时间操作,时间复杂度为 O(1)
  4. 计算最小移动次数,使用滑动窗口

    • 外层 for 循环遍历数组,时间复杂度为 O(n)
    • 内层 while 循环在最坏情况下会遍历整个数组,但由于 j 是递增的,每个元素最多被访问两次(一次在 for 循环中,一次在 while 循环中),所以内层循环的总时间复杂度为 O(n)
    • 因此,滑动窗口部分的总时间复杂度为 O(n)

总时间复杂度

  • 排序操作:O(n log n)
  • 特殊处理和滑动窗口:O(n)

综合起来,代码的总时间复杂度为 O(n log n),其中 n 是数组 stones 的长度。

相关推荐
core5122 分钟前
PageRank 算法:互联网的“人气投票”
算法·pagerank
小白菜又菜5 分钟前
Leetcode 1523. Count Odd Numbers in an Interval Range
算法·leetcode
你们补药再卷啦33 分钟前
人工智能算法概览
人工智能·算法
cnxy18838 分钟前
围棋对弈Python程序开发完整指南:步骤3 - 气(Liberties)的计算算法设计
python·算法·深度优先
AndrewHZ1 小时前
【图像处理基石】什么是光栅化?
图像处理·人工智能·算法·计算机视觉·3d·图形渲染·光栅化
小白菜又菜1 小时前
Leetcode 944. Delete Columns to Make Sorted
算法·leetcode
我找到地球的支点啦1 小时前
Matlab系列(006) 一利用matlab保存txt文件和读取txt文件
开发语言·算法·matlab
Dev7z2 小时前
基于Matlab实现GRACE卫星重力数据的全球水储量变化估算与分析
人工智能·算法·matlab
爱喝热水的呀哈喽2 小时前
11题目汇总
算法
三斗米3 小时前
Transformer入门:一文读懂《Attention Is All You Need》
算法·架构