Maximum Number of Potholes That Can Be Fixed
MediumUpdated: Aug 2, 2025
Practice on:
Problem
You are given a string road, consisting only of characters "x" and ".", where each "x" denotes a pothole and each "." denotes a smooth road, and an integer budget.
In one repair operation, you can repair n consecutive potholes for a price of n + 1.
Return the maximum number of potholes that can be fixed such that the sum of the prices of all of the fixes doesn 't go over the given budget.
Examples
Example 1:
Input: road = "..", budget = 5
Output: 0
Explanation:
There are no potholes to be fixed.
Example 2:
Input: road = "..xxxxx", budget = 4
Output: 3
Explanation:
We fix the first three potholes (they are consecutive). The budget needed for
this task is `3 + 1 = 4`.
Example 3:
Input: road = "x.x.xxx...x", budget = 14
Output: 6
Explanation:
We can fix all the potholes. The total cost would be `(1 + 1) + (1 + 1) + (3 +
1) + (1 + 1) = 10` which is within our budget of 14.
Constraints:
1 <= road.length <= 10^51 <= budget <= 10^5 + 1roadconsists only of characters'.'and'x'.
Solution
Method 1 – Greedy Group Repair
Intuition
To maximize the number of potholes fixed within the budget, we should repair the smallest groups of consecutive potholes first, as their cost per pothole is lower. By sorting all groups of consecutive potholes by their size, we can greedily fix as many as possible.
Approach
- Parse the road string to find all groups of consecutive 'x' (potholes) and record their lengths.
- Sort these group lengths in ascending order.
- For each group, try to fix the entire group if the budget allows (cost = group size + 1).
- If the budget is not enough for the whole group, fix as many potholes as possible individually (each costs 2).
- Stop when the budget runs out.
- Return the total number of potholes fixed.
Code
C++
class Solution {
public:
int maxPotholesFixed(string road, int budget) {
vector<int> groups;
int n = road.size(), cnt = 0, ans = 0;
for (int i = 0; i <= n; ++i) {
if (i < n && road[i] == 'x') cnt++;
else if (cnt > 0) { groups.push_back(cnt); cnt = 0; }
}
sort(groups.begin(), groups.end());
for (int g : groups) {
int cost = g + 1;
if (budget >= cost) { ans += g; budget -= cost; }
else {
int canFix = min(g, budget / 2);
ans += canFix;
break;
}
}
return ans;
}
};
Go
func maxPotholesFixed(road string, budget int) int {
groups := []int{}
cnt, ans := 0, 0
for i := 0; i <= len(road); i++ {
if i < len(road) && road[i] == 'x' {
cnt++
} else if cnt > 0 {
groups = append(groups, cnt)
cnt = 0
}
}
sort.Ints(groups)
for _, g := range groups {
cost := g + 1
if budget >= cost {
ans += g
budget -= cost
} else {
canFix := g
if budget/2 < g {
canFix = budget / 2
}
ans += canFix
break
}
}
return ans
}
Java
class Solution {
public int maxPotholesFixed(String road, int budget) {
List<Integer> groups = new ArrayList<>();
int cnt = 0, ans = 0, n = road.length();
for (int i = 0; i <= n; i++) {
if (i < n && road.charAt(i) == 'x') cnt++;
else if (cnt > 0) { groups.add(cnt); cnt = 0; }
}
Collections.sort(groups);
for (int g : groups) {
int cost = g + 1;
if (budget >= cost) { ans += g; budget -= cost; }
else {
int canFix = Math.min(g, budget / 2);
ans += canFix;
break;
}
}
return ans;
}
}
Kotlin
class Solution {
fun maxPotholesFixed(road: String, budget: Int): Int {
val groups = mutableListOf<Int>()
var cnt = 0
var ans = 0
for (i in 0..road.length) {
if (i < road.length && road[i] == 'x') cnt++
else if (cnt > 0) { groups.add(cnt); cnt = 0 }
}
groups.sort()
var b = budget
for (g in groups) {
val cost = g + 1
if (b >= cost) { ans += g; b -= cost }
else {
val canFix = minOf(g, b / 2)
ans += canFix
break
}
}
return ans
}
}
Python
class Solution:
def maxPotholesFixed(self, road: str, budget: int) -> int:
groups: list[int] = []
cnt: int = 0
ans: int = 0
n: int = len(road)
for i in range(n + 1):
if i < n and road[i] == 'x':
cnt += 1
elif cnt > 0:
groups.append(cnt)
cnt = 0
groups.sort()
for g in groups:
cost = g + 1
if budget >= cost:
ans += g
budget -= cost
else:
can_fix = min(g, budget // 2)
ans += can_fix
break
return ans
Rust
impl Solution {
pub fn max_potholes_fixed(road: String, mut budget: i32) -> i32 {
let mut groups = vec![];
let mut cnt = 0;
let mut ans = 0;
let n = road.len();
let chars: Vec<char> = road.chars().collect();
for i in 0..=n {
if i < n && chars[i] == 'x' {
cnt += 1;
} else if cnt > 0 {
groups.push(cnt);
cnt = 0;
}
}
groups.sort();
for g in groups {
let cost = g + 1;
if budget >= cost {
ans += g;
budget -= cost;
} else {
let can_fix = std::cmp::min(g, budget / 2);
ans += can_fix;
break;
}
}
ans
}
}
TypeScript
class Solution {
maxPotholesFixed(road: string, budget: number): number {
const groups: number[] = [];
let cnt = 0, ans = 0;
for (let i = 0; i <= road.length; i++) {
if (i < road.length && road[i] === 'x') cnt++;
else if (cnt > 0) { groups.push(cnt); cnt = 0; }
}
groups.sort((a, b) => a - b);
for (const g of groups) {
const cost = g + 1;
if (budget >= cost) { ans += g; budget -= cost; }
else {
const canFix = Math.min(g, Math.floor(budget / 2));
ans += canFix;
break;
}
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n log n)— We scan the road string once (O(n)) and sort the group sizes (O(k log k), wherekis the number of groups,k <= n). - 🧺 Space complexity:
O(n)— We store all group sizes, which in the worst case is up ton.