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

83 阅读3分钟

问题描述

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

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

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

解题思路分析:
这个问题可以看作是一个最小化移动次数的问题,我们的目标是将一组石子从它们初始的位置调整为连续的排列。通过移动石子,可以减少石子之间的空位,使它们形成一个连续的序列。

关键点

  1. 排序:首先,我们需要对石子的位置进行排序。这样,我们可以容易地分析石子之间的间隔,找出哪些空位是我们可以填补的。
  2. 空位计算:移动石子的目标是尽可能填补这些空位,使得石子的位置变得连续。因此,计算出这些空位的数量对于求解问题非常重要。
  3. 最大移动次数:最大移动次数等于可以填补的空位的数量。我们需要通过计算这些空位,判断可以进行的最大移动次数。

详细步骤

  1. 排序石子位置: 我们对石子的位置进行排序。通过排序,可以确保石子的位置是有序的,这样我们就能轻松地判断哪些位置之间是空位。
  2. 计算空位数量: 在排序后的石子位置中,空位的数量可以通过计算相邻石子之间的差值来获得。对于每一对相邻的石子,空位数就是它们之间差值减去 1。如果差值大于 1,就意味着有空位可以用来移动其他石子。
  3. 计算最大移动次数: 最大的移动次数就是所有空位数的总和。但要注意,如果石子的位置已经是连续的,那么没有空位,最大移动次数就是 0。
  4. 特殊情况处理: 如果只有 1 个石子,显然没有必要进行任何移动,因为已经是连续的了,返回 0。

算法步骤

  1. 对石子的当前位置进行排序。
  2. 计算从最小位置到最大位置之间的空位数量。
  3. 计算可以进行的最大移动次数,等于空位的数量。
  4. 返回结果。

复杂度分析

  • 时间复杂度:排序操作的时间复杂度是 O(n log n),后续的空位计算和判断操作是 O(n)。因此,总时间复杂度为 O(n log n)
  • 空间复杂度:只用了额外的几个常量空间,因此空间复杂度是 O(1)

完整代码:

#include <vector>
#include<bits/stdc++.h>
using namespace std;

int solution(vector<int>& stones) {
    if(stones.size()<2)
    {
       return 0;
    }
    // write code here
    sort(stones.begin(),stones.end());
    int res=stones[stones.size()-1]-stones[0]+1-stones.size();
    if(stones[0]+1!=stones[1]&&stones[stones.size()-1]-1!=stones[stones.size()-2]){
       int a=stones[1]-stones[0]-1;
       int b=stones[stones.size()-1]-stones[stones.size()-2]-1;
       int ans=min(a,b);
      // cout<<ans<<endl;
       res-=ans;
    }

    return res;
}

int main() {
    vector<int> v1 = {7, 4, 9};
    vector<int> v2 = {6, 5, 4, 3, 10};
    vector<int> v3 = {1, 2, 3, 4, 5};

    cout << (solution(v1) == 2) << endl;
    cout << (solution(v2) == 3) << endl;
    cout << (solution(v3) == 0) << endl;
    return 0;
}