LeetCode 2027: Minimum Moves to Convert String (Greedy Triple-Cover Scan)
LeetCode 2027StringGreedyToday we solve LeetCode 2027 - Minimum Moves to Convert String.
Source: https://leetcode.com/problems/minimum-moves-to-convert-string/
English
Problem Summary
Given a string s containing X and O, one move can pick any index and convert that character and the next two characters to O. Return the minimum number of moves to turn the whole string into all O.
Key Insight
When we see an X at position i, any optimal solution must cover it. The best greedy choice is to do one move starting at i, which converts i, i+1, i+2. Then we skip those three positions.
Algorithm
- Scan from left to right with index i.
- If s[i] == 'X', increase answer by 1 and do i += 3.
- Otherwise do i += 1.
- End when i reaches string length.
Complexity Analysis
Time: O(n), each character visited at most once.
Space: O(1).
Common Pitfalls
- Trying DP/backtracking although greedy is enough.
- Forgetting to jump by 3 after consuming an X.
- Overthinking boundary, because move naturally handles tail with available indices.
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public int minimumMoves(String s) {
int moves = 0;
for (int i = 0; i < s.length();) {
if (s.charAt(i) == 'X') {
moves++;
i += 3;
} else {
i++;
}
}
return moves;
}
}func minimumMoves(s string) int {
moves := 0
for i := 0; i < len(s); {
if s[i] == 'X' {
moves++
i += 3
} else {
i++
}
}
return moves
}class Solution {
public:
int minimumMoves(string s) {
int moves = 0;
for (int i = 0; i < (int)s.size();) {
if (s[i] == 'X') {
++moves;
i += 3;
} else {
++i;
}
}
return moves;
}
};class Solution:
def minimumMoves(self, s: str) -> int:
moves = 0
i = 0
while i < len(s):
if s[i] == 'X':
moves += 1
i += 3
else:
i += 1
return movesvar minimumMoves = function(s) {
let moves = 0;
for (let i = 0; i < s.length; ) {
if (s[i] === 'X') {
moves++;
i += 3;
} else {
i++;
}
}
return moves;
};中文
题目概述
给定仅由 X 和 O 组成的字符串 s。一次操作可选择任意位置,把该位置及后面两个位置都变成 O。求把整串变成全 O 的最少操作次数。
核心思路
从左到右扫描,遇到第一个 X 时必须覆盖它。贪心地从当前位置执行一次操作最优,因为这次操作正好能覆盖连续 3 个字符,然后索引直接跳过这 3 位。
算法步骤
- 用指针 i 从左到右遍历。
- 若 s[i] == 'X',答案加 1,并执行 i += 3。
- 否则执行 i += 1。
- 遍历结束返回答案。
复杂度分析
时间复杂度:O(n),每个字符最多访问一次。
空间复杂度:O(1)。
常见陷阱
- 把问题做成 DP 或回溯,复杂化了。
- 命中 X 后忘记跳 3 步。
- 对结尾边界过度担心,按规则扫描即可正确处理。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public int minimumMoves(String s) {
int moves = 0;
for (int i = 0; i < s.length();) {
if (s.charAt(i) == 'X') {
moves++;
i += 3;
} else {
i++;
}
}
return moves;
}
}func minimumMoves(s string) int {
moves := 0
for i := 0; i < len(s); {
if s[i] == 'X' {
moves++
i += 3
} else {
i++
}
}
return moves
}class Solution {
public:
int minimumMoves(string s) {
int moves = 0;
for (int i = 0; i < (int)s.size();) {
if (s[i] == 'X') {
++moves;
i += 3;
} else {
++i;
}
}
return moves;
}
};class Solution:
def minimumMoves(self, s: str) -> int:
moves = 0
i = 0
while i < len(s):
if s[i] == 'X':
moves += 1
i += 3
else:
i += 1
return movesvar minimumMoves = function(s) {
let moves = 0;
for (let i = 0; i < s.length; ) {
if (s[i] === 'X') {
moves++;
i += 3;
} else {
i++;
}
}
return moves;
};
Comments