Every day a leetcode
题目来源:605. 种花问题
解法1:贪心
贪心思想:在不打破种植规则的情况下种入尽可能多的花,然后用“最大种植数量”和“所需要种植数量”进行大小比较即可。
设地块长度为n,种花的情况可分为4种:
- 全是地块全部没有花,则可以种植(n+1)/2朵花
- 若地块i上有原有的第一朵花,则i之前可以种植i/2朵花
- 若地块a和b(a<b)都有花,则a和b之间可以种植(b-a-2)/2朵花
- 若地块j上有原有的最后一株花,则i之前可以种植(n-j-1)/2朵花
我们用prev记录前一朵花的下标,初始化为-1。
使用变量count记录最大种植数量,初始化为0。
遍历一次数组,每次遇到一朵花(flowerbed[i] == 1)就视情况更新count,别忘了更新prev=i:
- 若prev为-1,说明是第一朵花,则count+=i/2
- 否则,说明要在prev和i之间种花,count+=(i-prev-2)/2
特殊情况:遍历一次数组后prev仍然为-1,说明全是地块全部没有花,则可以种植(n+1)/2朵花。否则prev为地块最后一朵花的位置,count+=(n-prev-1)/2。
特判:开始时比较n和(flowerbed.size()+1)/2,若n>(flowerbed.size()+1)/2,说明一定不能在不打破种植规则的情况下种入n朵花,返回false。
代码:
class Solution {
public:
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
if(n>(flowerbed.size()+1)/2) return false;
int count=0;
int prev=-1;
for(int i=0;i<flowerbed.size();i++)
{
if(flowerbed[i] == 1)
{
if(prev<0) count+=i/2;
else count+=(i-prev-2)/2;
prev=i;
}
}
if(prev<0) count=(flowerbed.size()+1)/2;
else count+=(flowerbed.size()-prev-1)/2;
return n<=count;
}
};
结果:
复杂度分析:
时间复杂度:O(n),需要遍历一次数组。
空间复杂度:O(1),只用到了count和prev这2个变量。
优化:
不需要分开判断第一朵花还是其他位置的花。
对于一段长度为zero的连续的0区间,其可以种的花的数量=(zero+1)/2,遍历一次数组做计算即可。
class Solution {
public:
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
if(flowerbed.size() == 0) return n == 0;
if(n>(flowerbed.size()+1)/2) return false;
int zero=0;//当前全0区段中连续0的数量
zero++;//区间最左边没有花,可以认为在其左边存在一个虚无的0
int count=0;//可以种的花的数量
for(int i=0;i<flowerbed.size();i++)
{
if(flowerbed[i] == 0) zero++;
else
{
//对于每一段连续0区间,可以种的花的数量=(区间长度-1)/2
count+=(zero-1)/2;
if(n<=count) return true;
zero=0;
}
}
zero++;//区间最右边没有花,可以认为在其右边存在一个虚无的0
count+=(zero-1)/2;
return n<=count;
}
};
结果: