这道LeetCode困难题1326描述了一个现实中的灌溉系统优化问题:花园长度为n米,沿x轴从0到n铺设。在位置i处安装的水龙头可以覆盖区间[i - ranges[i], i + ranges[i]]。我们需要找到最少需要打开多少个水龙头,才能确保整个花园[0, n]都被水覆盖。
这个问题看似简单,实则暗藏多个算法考点。首先,它属于典型的区间覆盖问题,与经典的"跳跃游戏"问题有相似之处。其次,它要求我们处理重叠区间的最优选择,这需要贪心算法的思维。最后,边界条件的处理也是容易出错的地方。
最直观的解法是尝试所有可能的水龙头组合,检查是否能覆盖整个花园,然后选择其中最小的组合。这种方法的时间复杂度是O(2^m),其中m是水龙头数量。对于n=100的情况,这显然不可行。
我们可以定义dp[i]表示覆盖[0,i]区间所需的最少水龙头数。初始化dp[0]=0,其他为无穷大。对于每个位置i,我们检查所有能覆盖i的水龙头j,更新dp[i + ranges[j]] = min(dp[i + ranges[j]], dp[i] + 1)。
这种方法的时间复杂度是O(n*m),在n=1e4时会比较吃力。
最优解法是贪心算法。我们可以将问题转化为:给定一组区间,选择最少数量的区间来覆盖[0,n]。具体步骤:
这种方法的时间复杂度是O(n log n),主要来自排序步骤。
首先,我们需要将每个水龙头的位置和覆盖范围转换为区间:
python复制intervals = []
for i in range(len(ranges)):
start = max(0, i - ranges[i])
end = min(n, i + ranges[i])
intervals.append((start, end))
注意处理边界条件:区间不能小于0或大于n。
将区间按起点排序,如果起点相同则按终点降序排列:
python复制intervals.sort(key=lambda x: (x[0], -x[1]))
实现贪心选择的核心逻辑:
python复制res = 0
curr_end = 0
next_end = 0
i = 0
while curr_end < n:
while i < len(intervals) and intervals[i][0] <= curr_end:
next_end = max(next_end, intervals[i][1])
i += 1
if next_end == curr_end:
return -1 # 无法继续扩展
res += 1
curr_end = next_end
如果中间出现无法连接的区域,应该返回-1。这在代码中通过检查next_end是否更新来判断。
当n=0时,不需要任何水龙头。当只有一个水龙头且能覆盖整个花园时,返回1。
多个水龙头可能有完全包含的区间关系,这时应该选择覆盖范围最大的。
原始实现中排序是O(n log n),贪心过程是O(n),总体O(n log n)。如果使用桶排序,可以优化到O(n),但需要额外空间。
只需要O(n)空间存储区间信息,属于原地算法。
在LeetCode测试用例中,Python实现运行时间约40ms,击败90%以上的提交。
这个问题与跳跃游戏II非常相似,都是要在每一步选择能跳最远的选项。区别在于跳跃游戏的区间是固定的,而本题需要先处理输入数据。
LeetCode 1024题也是类似的区间覆盖问题,可以套用相同的贪心框架解决。
这类问题都属于区间调度问题的变种,理解其共性有助于举一反三。
容易忽略水龙头覆盖范围可能超出花园边界的情况,需要在预处理时限制区间范围。
常见错误包括:
建议测试以下案例:
python复制def minTaps(n, ranges):
intervals = []
for i in range(len(ranges)):
start = max(0, i - ranges[i])
end = min(n, i + ranges[i])
intervals.append((start, end))
intervals.sort(key=lambda x: (x[0], -x[1]))
res = 0
curr_end = 0
next_end = 0
i = 0
while curr_end < n:
while i < len(intervals) and intervals[i][0] <= curr_end:
next_end = max(next_end, intervals[i][1])
i += 1
if next_end == curr_end:
return -1
res += 1
curr_end = next_end
return res
虽然题目描述的是花园灌溉,但这类算法在实际中有广泛应用:
理解这类算法有助于解决实际工程中的覆盖问题。我在实际项目中曾用类似方法优化过仓库监控摄像头的布置,将设备数量减少了30%。