Facebook Pixel

3119. Maximum Number of Potholes That Can Be Fixed ๐Ÿ”’


Problem Description

You are given a string road, consisting only of characters "x" and ".", where each "x" denotes a pothole and each "." denotes a smooth road, along with 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 costs of all repairs doesn't exceed the given budget.

Intuition

To solve this problem optimally, we need to utilize a counting and greedy approach. The idea is to count the number of consecutive potholes of each length and attempt to repair larger groups first since they offer a better ratio of potholes repaired to cost incurred.

  1. First, convert each segment of consecutive potholes into a count and store these counts in an array called cnt.
  2. cnt[k] indicates the number of segments of consecutive potholes of length k.
  3. Start with the longest sequences of potholes (k) and see how many of these you can afford to repair based on the budget.
  4. This is done by calculating t, which is the minimum between the number of segments cnt[k] and how many your budget allows (budget // (k + 1)). Fix as many as t segments of length k.
  5. For each segment repaired, reduce the budget accordingly and increase the count of repaired potholes (ans).
  6. If there are more segments than you can afford to fix, consider them as shorter segments for future budget calculations by updating cnt[k-1].
  7. Repeat the process for smaller segments until the budget is exhausted or all segments are considered.

By following the above logic, you maximize the number of potholes repaired within the given budget by focusing on cost-effective repairs.

Learn more about Greedy and Sorting patterns.

Solution Approach

The solution implements a counting and greedy technique to fix potholes optimally. Here's a step-by-step walkthrough of the approach:

  1. Augment the Road: Append a "." to the road string to ensure any trailing pothole segments are processed.

  2. Initialize Variables:

    • Create an array cnt of size n where n is the length of the augmented road. This will store the counts of consecutive pothole segments.
    • Use a variable k to keep track of the current length of a consecutive pothole segment.
    • Set ans to 0 to track the total number of potholes repaired.
  3. Count Consecutive Potholes:

    • Traverse the road character by character using a loop.
    • Increment k for every pothole "x" encountered.
    • When a smooth road "." is encountered after a sequence of potholes, update cnt[k] by the number of such sequences and reset k to 0.
  4. Repair Potholes Greedily:

    • Iterate over possible lengths of pothole sequences from n-1 to 1.
    • For each length k, determine the number of segments t that can be completely fixed given the current budget.
      • This is calculated by t = min(budget // (k + 1), cnt[k]).
    • Increment ans by t * k because for each segment of length k, k potholes are repaired.
    • Decrease the budget by t * (k + 1), accounting for the segments repaired.
    • If cnt[k] > t, add the leftover potholes to the next smaller group of potholes by updating cnt[k-1].
  5. End Condition:

    • Stop the process if the budget is exhausted.

The algorithm prioritizes longer segments first due to their cost efficiency, ensuring the maximum number of potholes are repaired within the given budget.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a simple example to illustrate the approach. Consider the following input:

  • String road: "..xx..xxx...x"
  • Budget: 6

Step 1: Augment the Road

To ensure all potholes are considered, append a "." to the road. It becomes "..xx..xxx...x.".

Step 2: Initialize Variables

Create an array, cnt, initialized to zeros with size equal to the length of the augmented road. Initialize k = 0 to count consecutive potholes and ans = 0 to sum repaired potholes.

Step 3: Count Consecutive Potholes

Iterate over the string:

  • For index 2: encounter "x", increment k to 1.
  • For index 3: encounter another "x", increment k to 2.
  • For index 4: encounter "." (end of segment), update cnt[2] to 1, reset k to 0.
  • For index 6: encounter "x", increment k to 1.
  • For index 7: another "x", increment k to 2.
  • For index 8: another "x", increment k to 3.
  • For index 9: encounter "." (end of segment), update cnt[3] to 1, reset k to 0.
  • For index 12: encounter "x", increment k to 1.
  • For index 13: encounter "." (end of segment), update cnt[1] to 1, reset k to 0.

cnt now looks like [0, 1, 1, 1, ..., 0].

Step 4: Repair Potholes Greedily

Starting from length 3 downwards:

  • For k = 3: Can fix t = min(budget // (3+1), cnt[3]) = min(6 // 4, 1) = 1. Repair this segment:

    • Update ans += 3 * 1 = 3.
    • Adjust budget -= 4 * 1 = 2.
    • If cnt[3] > t, add excess to cnt[2]. In this case, it's not needed.
  • For k = 2: Can fix t = min(budget // (2+1), cnt[2]) = min(2 // 3, 1) = 0. Budget doesn't allow repair of length-2 segments.

  • For k = 1: Can fix t = min(budget // (1+1), cnt[1]) = min(2 // 2, 1) = 1. Repair this segment:

    • Update ans += 1 * 1 = 4.
    • Adjust budget -= 2 * 1 = 0.

Step 5: End Condition

The budget is exhausted, so stop the process.

Result

The maximum number of potholes repaired is 4.

Solution Implementation

1class Solution:
2    def maxPotholes(self, road: str, budget: int) -> int:
3        # Add a sentinel character at the end of the road to handle the last group of potholes
4        road += "."
5      
6        # Determine the length of the modified road
7        n = len(road)
8      
9        # Initialize a list to keep count of the number of segments of continuous potholes of length i
10        cnt = [0] * n
11      
12        # Variable to keep track of the current streak of continuous potholes
13        k = 0
14      
15        # Traverse each character in the road string
16        for c in road:
17            if c == "x":
18                # Increment the streak if the character is a pothole
19                k += 1
20            elif k:
21                # Record the streak count and reset the streak
22                cnt[k] += 1
23                k = 0
24      
25        # Initialize the answer to account for the maximum number of potholes that can be fixed
26        ans = 0
27      
28        # Iterate over the cnt list from the end to the beginning
29        for k in range(n - 1, 0, -1):
30            if cnt[k] == 0:
31                # Continue if there are no segments of length k
32                continue
33              
34            # Determine the maximum number of full groups of length (k + 1) that can be fixed
35            t = min(budget // (k + 1), cnt[k])
36          
37            # Increase the answer by the number of potholes fixed in these full groups
38            ans += t * k
39          
40            # Deduct the cost for fixing these full groups from the budget
41            budget -= t * (k + 1)
42          
43            # Stop if there is no budget left
44            if budget == 0:
45                break
46              
47            # Add the remainder of the groups that couldn't be fully fixed to the next lower count
48            cnt[k - 1] += cnt[k] - t
49      
50        return ans
51
1class Solution {
2    public int maxPotholes(String road, int budget) {
3        // Append a non-'x' character to handle trailing potholes
4        road += ".";
5        int n = road.length();
6      
7        // Array to keep track of contiguous pothole counts
8        int[] cnt = new int[n];
9        int contiguous = 0;
10      
11        // Iterate through the road string
12        for (char ch : road.toCharArray()) {
13            if (ch == 'x') {
14                // Increase count if pothole is found
15                ++contiguous;
16            } else if (contiguous > 0) {
17                // Record contiguous potholes and reset counter
18                ++cnt[contiguous];
19                contiguous = 0;
20            }
21        }
22      
23        int maxPotholesFixed = 0;
24      
25        // Process from longest contiguous segment to shortest
26        for (contiguous = n - 1; contiguous > 0 && budget > 0; --contiguous) {
27            // Calculate the maximum number of contiguous segments fixable
28            int fixableSegments = Math.min(budget / (contiguous + 1), cnt[contiguous]);
29          
30            // Add total potholes fixed in this step
31            maxPotholesFixed += fixableSegments * contiguous;
32          
33            // Deduct budget used for fixing
34            budget -= fixableSegments * (contiguous + 1);
35          
36            // Adjust count array to shift unfixable segments to the next smaller length
37            cnt[contiguous - 1] += cnt[contiguous] - fixableSegments;
38        }
39      
40        return maxPotholesFixed;
41    }
42}
43
1#include <vector>
2#include <string>
3#include <algorithm>
4
5class Solution {
6public:
7    int maxPotholes(std::string road, int budget) {
8        road.push_back('.'); // Append a '.' to handle the last section of potholes easily.
9        int n = road.size();
10        std::vector<int> count(n, 0); // Count of contiguous pothole segments of different lengths.
11        int contiguousCount = 0; // Length of the current contiguous segment of 'x'.
12
13        // Traverse the road to count contiguous segments of potholes ('x').
14        for (char& c : road) {
15            if (c == 'x') {
16                ++contiguousCount; // Increment length of contiguous 'x' segment.
17            } else if (contiguousCount) {
18                ++count[contiguousCount]; // Record the count of this segment length.
19                contiguousCount = 0; // Reset for the next segment.
20            }
21        }
22
23        int maxFixedPotholes = 0; // Maximum potholes that can be fixed with the budget.
24      
25        // Work backward through potential segment lengths to maximize potholes fixed.
26        for (int length = n - 1; length > 0 && budget > 0; --length) {
27            // Calculate how many segments of this length can be fixed within budget.
28            int fixable = std::min(budget / (length + 1), count[length]);
29            maxFixedPotholes += fixable * length; // Increase fixed pothole count.
30            budget -= fixable * (length + 1); // Decrease budget according to segments fixed.
31            count[length - 1] += count[length] - fixable; // Roll over any unfixed segments.
32        }
33
34        return maxFixedPotholes; // Return the total count of fixed potholes.
35    }
36};
37
1// Function to calculate the maximum number of potholes that can be fixed within a given budget.
2function maxPotholes(road: string, budget: number): number {
3    // Append a '.' to the road string to handle the edge case of potholes at the end of the road
4    road += '.';
5
6    // Length of the modified road string
7    const n: number = road.length;
8
9    // Array to count contiguous sequences of 'x' (potholes) of each length
10    const cnt: number[] = Array(n).fill(0);
11
12    let k: number = 0; // Variable to count current contiguous 'x' length
13
14    // Iterate over each character in the road string
15    for (const c of road) {
16        if (c === 'x') {
17            // Count contiguous potholes
18            ++k;
19        } else if (k > 0) {
20            // When a sequence of potholes ends, update the count array
21            ++cnt[k];
22            k = 0; // Reset count
23        }
24    }
25
26    let ans: number = 0; // Variable to store the maximum number of potholes fixed
27
28    // Iterate from largest possible contiguous pothole sequence downwards
29    for (k = n - 1; k > 0 && budget > 0; --k) {
30        // Calculate how many sequences of length 'k' can be fixed within the budget
31        const t: number = Math.min(Math.floor(budget / (k + 1)), cnt[k]);
32
33        // Increment the answer by the number of potholes fixed
34        ans += t * k;
35
36        // Reduce the budget by the cost of fixing the potholes
37        budget -= t * (k + 1);
38
39        // Add remaining sequences of current length to the next lower length
40        cnt[k - 1] += cnt[k] - t;
41    }
42
43    return ans; // Return the maximum number of potholes fixed
44}
45

Time and Space Complexity

The time complexity of the code is O(n), where n is the length of the string road. This is because the code iterates through the string road a few times: once to count the sequence of potholes and once more to calculate the maximum number of potholes that can be filled within the given budget.

The space complexity is also O(n), as the auxiliary array cnt used in the code has a size proportional to n. This array is utilized to keep track of the lengths of contiguous pothole segments.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

Which of the following is a min heap?


Recommended Readings

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!


Load More