LeetCode 1033: Moving Stones Until Consecutive (Gap Analysis)
LeetCode 1033MathGreedyToday we solve LeetCode 1033 - Moving Stones Until Consecutive.
Source: https://leetcode.com/problems/moving-stones-until-consecutive/
English
Problem Summary
We have three stones at positions a, b, c. In one move, pick an endpoint stone and place it at any empty position strictly between the other two stones. Return minimum and maximum moves needed to make the stones consecutive.
Key Insight
Sort positions as x < y < z. The result only depends on the two gaps: left = y - x and right = z - y.
Formulas
Maximum moves: each move can shrink total span by at most 1 from an endpoint, so
maxMoves = (z - x - 2).
Minimum moves:
- If already consecutive (z - x == 2), answer is 0.
- If one gap is at most 2 (left <= 2 or right <= 2), answer is 1 (special near-consecutive case).
- Otherwise answer is 2.
Complexity Analysis
Time: O(1).
Space: O(1).
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public int[] numMovesStones(int a, int b, int c) {
int[] s = new int[]{a, b, c};
java.util.Arrays.sort(s);
int x = s[0], y = s[1], z = s[2];
int minMoves;
if (z - x == 2) {
minMoves = 0;
} else if (y - x <= 2 || z - y <= 2) {
minMoves = 1;
} else {
minMoves = 2;
}
int maxMoves = z - x - 2;
return new int[]{minMoves, maxMoves};
}
}import "sort"
func numMovesStones(a int, b int, c int) []int {
s := []int{a, b, c}
sort.Ints(s)
x, y, z := s[0], s[1], s[2]
minMoves := 0
if z-x == 2 {
minMoves = 0
} else if y-x <= 2 || z-y <= 2 {
minMoves = 1
} else {
minMoves = 2
}
maxMoves := z - x - 2
return []int{minMoves, maxMoves}
}class Solution {
public:
vector<int> numMovesStones(int a, int b, int c) {
vector<int> s = {a, b, c};
sort(s.begin(), s.end());
int x = s[0], y = s[1], z = s[2];
int minMoves;
if (z - x == 2) {
minMoves = 0;
} else if (y - x <= 2 || z - y <= 2) {
minMoves = 1;
} else {
minMoves = 2;
}
int maxMoves = z - x - 2;
return {minMoves, maxMoves};
}
};class Solution:
def numMovesStones(self, a: int, b: int, c: int) -> List[int]:
x, y, z = sorted([a, b, c])
if z - x == 2:
min_moves = 0
elif y - x <= 2 or z - y <= 2:
min_moves = 1
else:
min_moves = 2
max_moves = z - x - 2
return [min_moves, max_moves]var numMovesStones = function(a, b, c) {
const s = [a, b, c].sort((m, n) => m - n);
const [x, y, z] = s;
let minMoves;
if (z - x === 2) {
minMoves = 0;
} else if (y - x <= 2 || z - y <= 2) {
minMoves = 1;
} else {
minMoves = 2;
}
const maxMoves = z - x - 2;
return [minMoves, maxMoves];
};中文
题目概述
给定三颗石子的位置 a、b、c。每次操作只能移动某个端点石子,并且新位置必须严格落在另外两颗石子之间的空位上。求把三颗石子变成连续位置所需的最小和最大操作次数。
核心思路
先排序得到 x < y < z,只需要看两个间隔:left = y - x、right = z - y。
公式推导
最大次数:总跨度内部空位数量是 z - x - 2,每次最多消掉 1 个空位,因此
maxMoves = z - x - 2。
最小次数:
- 若已经连续(z - x == 2),最小次数是 0。
- 若某一侧间隔不超过 2(left <= 2 或 right <= 2),一次就能完成,最小次数是 1。
- 其余情况需要 2 次。
复杂度分析
时间复杂度:O(1)。
空间复杂度:O(1)。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public int[] numMovesStones(int a, int b, int c) {
int[] s = new int[]{a, b, c};
java.util.Arrays.sort(s);
int x = s[0], y = s[1], z = s[2];
int minMoves;
if (z - x == 2) {
minMoves = 0;
} else if (y - x <= 2 || z - y <= 2) {
minMoves = 1;
} else {
minMoves = 2;
}
int maxMoves = z - x - 2;
return new int[]{minMoves, maxMoves};
}
}import "sort"
func numMovesStones(a int, b int, c int) []int {
s := []int{a, b, c}
sort.Ints(s)
x, y, z := s[0], s[1], s[2]
minMoves := 0
if z-x == 2 {
minMoves = 0
} else if y-x <= 2 || z-y <= 2 {
minMoves = 1
} else {
minMoves = 2
}
maxMoves := z - x - 2
return []int{minMoves, maxMoves}
}class Solution {
public:
vector<int> numMovesStones(int a, int b, int c) {
vector<int> s = {a, b, c};
sort(s.begin(), s.end());
int x = s[0], y = s[1], z = s[2];
int minMoves;
if (z - x == 2) {
minMoves = 0;
} else if (y - x <= 2 || z - y <= 2) {
minMoves = 1;
} else {
minMoves = 2;
}
int maxMoves = z - x - 2;
return {minMoves, maxMoves};
}
};class Solution:
def numMovesStones(self, a: int, b: int, c: int) -> List[int]:
x, y, z = sorted([a, b, c])
if z - x == 2:
min_moves = 0
elif y - x <= 2 or z - y <= 2:
min_moves = 1
else:
min_moves = 2
max_moves = z - x - 2
return [min_moves, max_moves]var numMovesStones = function(a, b, c) {
const s = [a, b, c].sort((m, n) => m - n);
const [x, y, z] = s;
let minMoves;
if (z - x === 2) {
minMoves = 0;
} else if (y - x <= 2 || z - y <= 2) {
minMoves = 1;
} else {
minMoves = 2;
}
const maxMoves = z - x - 2;
return [minMoves, maxMoves];
};
Comments