这个博客不是《石子移动问题》的解答,《石子移动问题》里求的是最大值,这里探讨一下最小值问题。AI刷题记录 | 石子移动问题先贴一下此题通过的代码(JAVA版本) 此题直接使用右侧AI提供的思路来写是无法通过的,正 - 掘金 (juejin.cn)这个博客记录了最大值的解法。
贴一下求解最小值问题的代码(JAVA版本)
题目参考力扣1040
class Solution {
public int[] numMovesStonesII(int[] stones) {
//最大石子的移动数
Arrays.sort(stones);
int max = 0;
//计算有多少个空位
int n = stones.length;
int spand = stones[n-1] - stones[0] + 1;
int remain = spand - n;
max = Math.max(remain - (stones[1]-stones[0]-1),remain-(stones[n-1]-stones[n-2]-1));
//最小的石子移动数
int start = 0,end = 0;
int cnt = 1;
int min = max;
while(end<n){
if(stones[end] - stones[start] + 1<n){
end++;
cnt++;
}else if(stones[end] - stones[start] + 1==n){
if(cnt == n-1){
min = 1;
}else{
min = Math.min(min,n-cnt);
}
end++;
start++;
}else{
if(cnt == n-1){
min = 2;
}else{
min = Math.min(min,n-cnt+1);
}
start++;
cnt--;
}
}
return new int[]{min,max};
}
}
思路
这道题的核心思想是将所有石子移动到一个长度为 n 的窗口内,使得窗口中的石子最终连续排列。为了最小化移动次数,我们首先分析各种情况,并通过合理选择窗口和移动策略来确定最少的操作数。
关键分析:
- 窗口中的连续石子:我们需要找到一个长度为 n 的窗口,其中尽可能多的石子已经处于连续排列的状态。如果窗口中有 n-1 个石子已经连续,且剩余的一个石子与窗口中的某个石子之间的空位数为 1,则只需一次操作即可使所有石子连续。否则,若空位数大于 1,则需要两次操作:第一步移动一个石子填补空位,第二步将剩余的石子移动到连续区间中。
- 窗口选择:如果当前窗口中没有足够多的石子,或连续的石子不足,我们选择石子最多的窗口作为目标窗口。假设窗口中已有k 个石子,则需要 n-k 次操作才能将所有空位填满。
注意
此题需要注意当窗口内的连续石子达到n-1的情况。由于题目限制端点石子操作后必须不能再为端点石子,这样可能会出现端点石子无法一步到位,需要借助中间石子两步完成的情况。第一步,搭建一个中间石子,第二步再把端点石子归位。但是,如果窗口外面剩余的石子大于等于两个就不会有这种情况,这时候我们可以随意选择则窗口外的一个石子去充当中间石子,这一步并不会增加石子的移动次数。