题目
在 x 轴上有一个一维的花园。花园长度为 n,从点 0 开始,到点 n 结束。
花园里总共有 n + 1 个水龙头,分别位于 [0, 1, …, n] 。
给你一个整数 n 和一个长度为 n + 1 的整数数组 ranges ,其中 ranges[i] (下标从 0 开始)表示:如果打开点 i 处的水龙头,可以灌溉的区域为 [i - ranges[i], i + ranges[i]] 。
请你返回可以灌溉整个花园的 最少水龙头数目 。如果花园始终存在无法灌溉到的地方,请你返回 -1 。
示例 1:
输入:n = 5, ranges = [3,4,1,1,0,0]
输出:1
解释:
点 0 处的水龙头可以灌溉区间 [-3,3]
点 1 处的水龙头可以灌溉区间 [-3,5]
点 2 处的水龙头可以灌溉区间 [1,3]
点 3 处的水龙头可以灌溉区间 [2,4]
点 4 处的水龙头可以灌溉区间 [4,4]
点 5 处的水龙头可以灌溉区间 [5,5]
只需要打开点 1 处的水龙头即可灌溉整个花园 [0,5] 。
示例 2:
输入:n = 3, ranges = [0,0,0,0]
输出:-1
解释:即使打开所有水龙头,你也无法灌溉整个花园。
示例 3:
输入:n = 7, ranges = [1,2,1,0,2,1,0,1]
输出:3
示例 4:
输入:n = 8, ranges = [4,0,0,0,0,0,0,0,4]
输出:2
示例 5:
输入:n = 8, ranges = [4,0,0,0,4,0,0,0,4]
输出:1
提示:
1 <= n <= 10^4
ranges.length == n + 1
0 <= ranges[i] <= 100
解法一(深度优先搜索)
思路:核心就是找出可以覆盖[0,n]的最小数组个数,那就把数组的头按递归排序,通过头尾交集来检查区域之间是否连续
- 求出各个数据覆盖的区域
- 找出无效或者其它区域的子域,仅对有效区域进行计算
- 为了方便递归,先对所有区域的开端进行递增排序
- 对每个区域开始,从前到后依次进行递归查询,如果满足条件,则记录最小的值,是深度优先算法的思想。
- 时间复杂度:O(n2+n!),n2是主函数的前三步,n!是第四步的递归函数
- 空间复杂度:O(n),存储区域的数组r
这是个顺序思维,可以满足功能要求成功执行,但时间复杂度太高了,结果就是仅通过了13/31个测试用例,未通过的超时了,超时测试用例及代码如下:
68
[0,0,0,1,4,2,2,2,2,4,0,0,0,5,4,0,0,5,3,0,1,1,5,1,1,2,4,1,0,4,3,5,1,0,3,3,4,2,2,4,3,1,1,0,4,0,2,1,4,0,0,3,3,1,1,4,4,2,0,3,4,0,1,5,3,0,1,0,2]
public class Solution {
public int getLinkCount(int[,] r,List<int> rList,int count,int len)
{
int minTemp = len;
bool flag = true;
for (int i = 1; i < rList.Count; i++)
{
//区域不连续
if (r[rList[i - 1], 1] < r[rList[i], 0])
{
flag = false;
break;
}
}
if (flag && r[rList[0], 0] <= 0 && r[rList[rList.Count - 1], 1] >= len-1)
return rList.Count;
for(int i=count+1;i<len;i++)
{
//从前到后做深度优先搜索的递归
if(r[i,2] == 1)
{
rList.Add(i);
int tmp = getLinkCount(r, rList, i, len);
if (tmp > 0 && tmp < minTemp)
minTemp = tmp; ;
rList.Remove(i);
}
}
return minTemp;
}
public int MinTaps(int n, int[] ranges)
{
//求区域
int len = ranges.Length;
int[,] r = new int[len,3];
for(int i=0;i<len;i++)
{
r[i,0] = i - ranges[i];
r[i, 1] = i + ranges[i];
r[i, 2] = 1;//有效性
}
//求有效数据
for (int i = 0; i < len; i++)
{
if(r[i,2] == 0) continue;
for