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

Insert image description here

The range of the garden on the x-axis is [0,n], 0~n. There are faucets at n+1 discrete points. The range that the i-th faucet can water is [i-ranges[i], i+ranges[i] ]].
Find the minimum number of faucets that can water the entire garden.

Idea:

Method one :
greedy

First prepare the interval that each faucet can water, and
use an array to save all intervals. The array subscript is the starting point of the interval, and the array content is the end point of the interval.

Then traverse the array from left to right, and it will be similar to the 55-question Jump Game .
Use a variable canReach to represent the furthest distance that can be reached by the current faucet. preEnd represents the end point of the interval of the previous tap.

If the current position > preEnd, it means that a new faucet needs to be opened,
but if canReach <= preEnd (the farthest distance that can be reached from the previous faucet cannot reach the current position, as explained later), it means that it cannot be reached, and return -1.
Update preEnd to canReach (canReach has not been updated at this time, that is, preEnd is updated to the farthest range until the previous tap). Number of taps + 1.
Update canReach to a larger value compared to the end point of the current interval.

There is a special case that should be noted, which is the case of ranges[i]=0 in Example2.
Note that being able to water the entire garden means that not only the discrete points i, i+1, ... can be watered, but the continuous points between i and i+1 must also be in the interval.
And ranges[i] = 0 means that it can only be poured to the discrete point i itself. For example, you can water at points 1 and 2, but 1.1, 1.2, ... between them are not within the watering range.
Therefore, when processing the interval, canReach must be able to reach the current point to meet the conditions.

    public int minTaps(int n, int[] ranges) {
    
    
        int preEnd = 0;
        int canReach = 0;
        int[] startEnd = new int[n+1];
        int cnt = 0;

        for(int i = 0; i <= n; i++) {
    
    
            if(ranges[i] == 0) continue;
            int start = (i - ranges[i] < 0 ? 0 : i - ranges[i]);
            int end = (i + ranges[i] > n ? n : i + ranges[i]);
            startEnd[start] = end;
        }

        for(int i = 0; i <= n; i++) {
    
    
            if(i > preEnd) {
    
    
                if(canReach <= preEnd) return -1;
                cnt ++;
                preEnd = canReach;
            }
            if(startEnd[i] > canReach) canReach = startEnd[i];
        }
		//cnt是前一区间满足条件时在当前区间加的,最后一个区间没有下一区间去处理,所以要在最后处理一下
		//如果preEnd能到达最后位置,就不需要cnt+1,如果到不了,需要再cnt++,preEnd更新到canReach
        return cnt + (preEnd < n ? 1 : 0);
    }

Method two :

DP
dp[i] represents the number of faucets required to reach position i.
At the beginning, except dp[0], everything else is initialized to infinity.

Still calculate the watering interval of each faucet from left to right as above.
The minimum number of faucets required at each point in the interval dp[i] = min(dp[i], dp[starting point of the interval]+1). What does
this mean?
Because dp[0]=0, when updating the interval of faucet 0, dp[0]+1 will be used as the standard. Within the range that the faucet at 0 can pour, the number of faucets required at each point is updated as 1.
Assume that the first interval is [0,2], update as follows
1 1 1 Inf Inf Inf
If you enter the next interval [2,4], then at the position of 2, you can still maintain dp[2]=min (dp[2], dp[2]+1)=1.
When it reaches position 3, dp[3]=min(Inf,dp[2]+1) becomes 2 faucets.
Similarly, if the previous range cannot cover the following range, min(inf, inf+1) will occur.
Finally, dp[n] is returned. If dp[n] is Inf, it means that the entire garden cannot be watered, and -1 is returned.

    public int minTaps(int n, int[] ranges) {
    
    
        final int INF = 100000;
        int[] dp = new int[n+1];
        Arrays.fill(dp, INF);
        dp[0] = 0;

        for(int i = 0; i <= n; i++) {
    
    
            int start = (i-ranges[i] < 0 ? 0 : i-ranges[i]);
            int end = (i + ranges[i] > n ? n : i+ranges[i]);
            for(int j = start; j <= end; j++){
    
    
                dp[j] = Math.min(dp[j], dp[start]+1);
            }
        }
        return dp[n] == INF ? -1 : dp[n];
    }

Guess you like

Origin blog.csdn.net/level_code/article/details/132626870