题目

思路1
将花园的灌溉点看作区间,建立一个数组存储这些区间,即数组下标表示左区间,数组存储右区间。
贪心算法,last记录在当前区间中,再选择1个区间未来能到达的最远距离,cur记录当前选择了的区间们的右边距。
当i到达cur的时候,就需要增加选择的区间了。
如果增加了区间,都还停留原地,即走不动了,那就是无法到达终点。即i==last,已经到达最远点。
cpp
class Solution:
def minTaps(self, n: int, ranges: List[int]) -> int:
right_most = list(range(n+1))
for i,r in enumerate(ranges):
#记录每个区间的左右下标
start = max(0, i - r)
end = min(n, i + r)
#将区间的左下标作为i,保存右下标(并合并能被包含的区间)
right_most[start] = max(right_most[start], end)
last = ans = cur = 0
for i in range(n):
last = max(last, right_most[i])#记录能覆盖的最大距离
if i == cur:
cur = last
ans += 1
if i == last:
return -1
return ans
思路2
动态规划。
先计算出区间。
cpp
class Solution:
def minTaps(self, n: int, ranges: List[int]) -> int:
#使用dp[i]表示覆盖区间[0,i]所需要的最少区间数目
#新加入的区间是[startj,endj] 状态转移:dp[k] = min(dp[k], dp[startj]+1)
intervals = []
for i,r in enumerate(ranges):
start = max(0, i-r)
end = min(n, i+r) #这个题有个陷阱,虽然花园长n,但是实际上是有n+1个点,因此这个是n
intervals.append((start, end))
intervals.sort()
dp = [inf] * (n+1) #长度为n的花园,有n+1个区间,这里
dp[0] = 0 #表示从位置0到位置0需要的喷头为0 ,因为还没浇水区间
for start, end in intervals:
if dp[start] == inf:
return -1
for j in range(start, end+1):
dp[j] = min(dp[j], dp[start]+1)
return dp[n]