LeetCode从低效到高效,点击
一、题目描述:
题目要求
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。
来源:力扣(LeetCode)链接
示例
输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
二、思路分析:
本题是一道简单题,从数组的左边到右边便利一边就行,如果降低判断的复杂度是这道题值得讨论的问题,首先比较恶心的就是需要判断边界条件,我最早想到的就是使用挨个判断的方式,后面的时候通过研究这个排列,可以使用跳过的方式快速便利这个数组,具体思路打到了注释上.
三、AC 代码:
按照上面的思路很容易写出下面的暴力模拟代码:
// 这个写法就是老老实实的遍历判断
bool canPlaceFlowers_v1(vector<int> &flowerbed, int n)
{
auto i = flowerbed.begin();
while(i!=flowerbed.end()&&n>0){
if(i == flowerbed.begin()&&(!*i)&&(!(*(i+1)))){
n--;
*i=1;
}
else if(i == flowerbed.end()-1&&(!*i)&&(!(*(i-1)))){
n--;
*i=1;
}
else if((!(*(i+1)))&&(!(*(i-1)))&&(!(*i))){
n--;
*i=1;
}
i++;
}
return n <= 0;
}
但是,上述代码还有优化空间,可以复用一些变量,最终优化成下面这样
// 32 ms 17.1 MB
// 16ms 19.5mb
bool canPlaceFlowers(vector<int> &flowerbed, int n)
{
// 本题最少也要有一个for循环对数组进行一次遍历,本方法是通过一种跳跃的方式不需要完整的遍历一边数组
// 首先直接拿变量n做结束控制,使用不同的判断条件进行跳跃查询而不是用查询赋值再查询的策略
for (int i = 0; i < flowerbed.size() && n > 0;)
{
// 当查找到这个位置种花了,这就能得到这个位置不能种了,下一个位置也不能种,所以跳两个格子
if (flowerbed[i])
{
i += 2;
}
// 没中花且这个位置能中华的两件就是下面两个,但是这个地方种了花,下个地方就不能种了,所以跳两个格子
else if (i == flowerbed.size() - 1 || flowerbed[i + 1] == 0)
{
i += 2;
n--;
}
// 没中花且不能种花代表了下一个坑位是跳到下三个坑,因为+2虽然那个位置肯定没花,但也肯定不能种
else
{
i += 3;
}
}
return n <= 0;
}
四、总结:
通过这道题,我发现贪心算法中要求的每一步最优构成整体最优的更深的含义,正是因为不用判断左边,才可以在跳跃的时候不再需要判断左边的情况,保证左边都是空的,简化了判断次数.
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情