Leetcode 1326. Minimum Number of Taps to Open to Water a Garden

Problem Explanation:

You are given a garden of length 'n' and an array 'ranges' which represents taps at each point in the garden starting from point 0 to point n. The taps functionality is defined by the array 'ranges' where each tap can water the area [i - ranges[i], i + ranges[i]] if it was open where 'i' is the point where the tap is located. The main problem here is to find the minimum number of taps needed to water the whole garden. If the garden cannot be watered by any combination of open taps, return -1.

Let's consider an example where the length of garden n = 5, and ranges = [3,4,1,1,0,0]. Here we can see that when we open second tap alone it will cover all the points from 0 to 5. Hence the minimum number of taps to water the whole garden is 1.

Approach Explanation:

The key insight here is that even though the taps water different areas they can overlap and it might not be necessary to turn on every tap to water the full garden. Therefore, the problem is to find the minimum number of taps to ensure that every point in the garden gets water. This can be solved using a greedy approach where we always choose to turn on the tap that waters the maximum area that we have not already watered.

The solution starts by looping over the 'ranges' array and storing the maximum range each tap can cover from its position. This is stored in the new 'nums' array where each position in the array stands for a tap and the value represents how many units to its right it can water.

The next part of the algorithm deals with finding the minimum number of taps. A simple approach would be to start from the first tap and always turn on the tap that waters the furthest into the garden among all the taps that can water the area that is not yet covered. 'End' variable keeps track of how much of the garden has been watered. The 'farthest' variable stores how far into the garden we can water with the currently turned on taps. Every time we reach the end of a tap's watering range, we count it and update our end to be the furthest we can currently water up to. If, at any point, we can't water any further into the garden than we already have, then we return -1 as it means we are unable to water the whole garden.

Through this approach, we can calculate the minimum number of taps to be opened to water the whole garden.

Python Solution

1
2python
3class Solution:
4    def minTaps(self, n: int, ranges: List[int]) -> int:
5        nums = [0]*(n+1)
6        for i in range(len(ranges)):
7            left, right = max(0, i-ranges[i]), min(n, i+ranges[i])
8            nums[left] = max(nums[left], right-left)
9        ans = 0
10        end = 0
11        farthest = 0
12        for i in range(n):
13            farthest = max(farthest, i+nums[i])
14            if i == end:
15                ans += 1
16                end = farthest
17        if end == n:
18            return ans
19        else:
20            return -1

Java Solution

1
2java
3class Solution {
4    public int minTaps(int n, int[] ranges) {
5        int[] nums = new int[n + 1];
6        for (int i = 0; i <= n; i++) {
7            int l = Math.max(0, i - ranges[i]);
8            int r = Math.min(n, i + ranges[i]);
9            nums[l] = Math.max(nums[l], r - l);
10        }
11        int ans = 0, end = 0, farthest = 0;
12        for (int i = 0; i < n; i++) {
13            farthest = Math.max(farthest, i + nums[i]);
14            if (i == end) {
15                ans++;
16                end = farthest;
17            }
18        }
19        if (end == n) {
20            return ans;
21        } else {
22            return -1;
23        }
24    }
25}

C# Solution

1
2csharp
3public class Solution {
4    public int MinTaps(int n, int[] ranges) {
5        int[] nums = new int[n + 1];
6        for (int i = 0; i <= n; i++) {
7            int l = Math.Max(0, i - ranges[i]);
8            int r = Math.Min(n, i + ranges[i]);
9            nums[l] = Math.Max(nums[l], r - l);
10        }
11        int ans = 0, end = 0, farthest = 0;
12        for (int i = 0; i < n; i++) {
13            farthest = Math.Max(farthest, i + nums[i]);
14            if (i == end) {
15                ans++;
16                end = farthest;
17            }
18        }
19        if (end == n) {
20            return ans;
21        } else {
22            return -1;
23        }
24    }
25}

C++ Solution

1
2c++
3class Solution {
4public:
5    int minTaps(int n, vector<int>& ranges) {
6        vector<int> nums(n + 1);
7        for (int i = 0; i <= n; ++i) {
8            int l = max(0, i - ranges[i]);
9            int r = min(n, i + ranges[i]);
10            nums[l] = max(nums[l], r - l);
11        }
12        int ans = 0;
13        int end = 0;
14        int farthest = 0;
15        for (int i = 0; i < n; i++) {
16            farthest = max(farthest, i + nums[i]);
17            if (i == end) {
18                ++ans;
19                end = farthest;
20            }
21        }
22        return end == n ? ans : -1;
23    }
24};

JavaScript Solution

1
2javascript
3var minTaps = function(n, ranges) {
4    let nums = new Array(n + 1).fill(0);
5    for (let i = 0; i <= n; i++) {
6        let l = Math.max(0, i - ranges[i]);
7        let r = Math.min(n, i + ranges[i]);
8        nums[l] = Math.max(nums[l], r - l);
9    }
10    let ans = 0, end = 0, farthest = 0;
11    for (let i = 0; i < n; i++) {
12        farthest = Math.max(farthest, i + nums[i]);
13        if (i == end) {
14            ans++;
15            end = farthest;
16        }
17    }
18    if (end == n){
19        return ans;
20    } else {
21        return -1;
22    }
23}

In the solutions provided, all four primary languages (Python, Java, JavaScript, and C++) are used to solve the problem. The main algorithm focuses on finding the maximum range each tap can cover, followed by a greedy approach that iterates through the garden to determine the minimum number of taps required to water every point. This is done by always choosing the tap that waters the furthest part of the garden that hasn't been watered yet.

Each solution begins by initializing an array (or vector in the case of C++) to track the ranges that each tap can water. This is done by iterating through the given ranges, calculating the left and right boundaries for the current tap, and saving the maximum range that this tap can achieve.

After that, four variables are created to keep track of the number of taps used (ans), the furthest point watered by the current set of taps (end), and the furthest point that can be watered by any tap within the current range (farthest). For every tap that can water an unwatered part of the garden, the algorithm checks if the tap's range extends beyond the current end point. If this happens, the ans counter increases, signifying a new tap is used, and the end variable is updated to the farthest point.

The solution will return -1 if the garden cannot be completely watered; otherwise, the minimum number of taps (ans) is returned.

Each solution takes advantage of its language's specific syntax and capabilities, but the overall strategy remains the same. This makes the solution very robust and adaptable across different programming languages.

Therefore, these solutions comprehensively solve the problem using different programming languages and showcase how the same problem-solving approach can be successfully implemented in multiple languages.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫