问题描述
小S正在玩一个关于石子的游戏,给定了一些石子,它们位于一维数轴的不同位置,位置用数组 stones 表示。如果某个石子处于最小或最大的一个位置,我们称其为端点石子。
在每个回合,小S可以将一颗端点石子移动到一个未占用的位置,使其不再是端点石子。游戏继续,直到石子的位置变得连续,无法再进行任何移动操作。
你需要帮助小S找到可以移动的最大次数。
解题思路分析:
这个问题可以看作是一个最小化移动次数的问题,我们的目标是将一组石子从它们初始的位置调整为连续的排列。通过移动石子,可以减少石子之间的空位,使它们形成一个连续的序列。
关键点
- 排序:首先,我们需要对石子的位置进行排序。这样,我们可以容易地分析石子之间的间隔,找出哪些空位是我们可以填补的。
- 空位计算:移动石子的目标是尽可能填补这些空位,使得石子的位置变得连续。因此,计算出这些空位的数量对于求解问题非常重要。
- 最大移动次数:最大移动次数等于可以填补的空位的数量。我们需要通过计算这些空位,判断可以进行的最大移动次数。
详细步骤
- 排序石子位置: 我们对石子的位置进行排序。通过排序,可以确保石子的位置是有序的,这样我们就能轻松地判断哪些位置之间是空位。
- 计算空位数量: 在排序后的石子位置中,空位的数量可以通过计算相邻石子之间的差值来获得。对于每一对相邻的石子,空位数就是它们之间差值减去 1。如果差值大于 1,就意味着有空位可以用来移动其他石子。
- 计算最大移动次数: 最大的移动次数就是所有空位数的总和。但要注意,如果石子的位置已经是连续的,那么没有空位,最大移动次数就是 0。
- 特殊情况处理: 如果只有 1 个石子,显然没有必要进行任何移动,因为已经是连续的了,返回 0。
算法步骤
- 对石子的当前位置进行排序。
- 计算从最小位置到最大位置之间的空位数量。
- 计算可以进行的最大移动次数,等于空位的数量。
- 返回结果。
复杂度分析
- 时间复杂度:排序操作的时间复杂度是
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;
}