种花问题 图解题解
这道题到底在问什么
- 输入
- flowerbed=[1,0,0,0,1], n=1
- 输出
- true (中间的位置2左右都空,能种下 1 朵)
最优解:为什么这么做
一句话答案:LeetCode 605 种花问题:从左到右扫花坛,遇到空格且左右邻居都空(边界当空)就当场种一朵、计数,能种就种最后看够不够 n 朵,时间 O(n)、空间 O(1)。
能不能再塞下 n 朵,还不让花挨着
flowerbed 是一排花坛,0 是空格、1 是已经种了花,题目先保证眼下没有两朵花挨在一起。再给一个 n,问能不能在不破坏「任意两朵不相邻」的前提下补种 n 朵,返回 true 或 false。题面例子 flowerbed=[1,0,0,0,1]、n=1:中间的位置 2 左右都空,正好补得下 1 朵,答案是 true。
为什么不能数一数空格有几个就完事
空格的总数不等于能种的朵数。三个连着的空格 [0,0,0] 也只种得下两朵,头尾各一朵、中间那格被两边挤死;而空格一旦贴着花就更种不了,[1,0,1] 里那个 0 左右都是花,一朵也塞不进去。能不能落一朵,卡的是每个空格左右邻居的脸色,跟空格总共有几个没有直接关系。
遇到合法空位就立刻种,为什么不会亏
扫到一个空格,只要它左邻和右邻都空(在最左或最右,就把缺的那一侧当空),就当场种下、把这格记成 1,然后接着往右走。
留着不种没有半点好处:这格空着,对它右边格子的限制一点没松(限制只来自相邻格里有没有花);而现在就种,最多挡住紧挨的右邻那一格,可那一格本来也得靠这格空着才种得成,两者只能活一个。靠左先种,落下的朵数不会比拖到后面更少,所以见空位就落是对的。
翻成代码:种完要把这格真的改成 1
for 扫每一格,只在 flowerbed[i]==0 时才考虑;left =(i 是 0)或 flowerbed[i-1]==0,right =(i 是末格)或 flowerbed[i+1]==0,两个都成立就 flowerbed[i]=1、count 加一。扫完 return count ≥ n。最容易漏的一步是种下后不改数组:种了却不把这格置 1,下一格判左邻时还以为这里空着,可能把两朵种成相邻。
跟着 [1,0,0,0,1]、n=1 逐格推下去
从左往右一格格看。位置 0 是花(1),跳过。位置 1 空,左邻 flowerbed[0]=1 是花,种下去就相邻,跳过。位置 2 空,左邻 flowerbed[1]=0、右邻 flowerbed[3]=0,两侧都空,种下一朵,count 变 1,把 flowerbed[2] 记成 1。位置 3 空,但左邻 flowerbed[2] 刚变成 1,跳过。位置 4 是花,跳过。扫完 count=1,1 ≥ 1,返回 true。
边界那侧算空,种完别忘改数组
最左格没有左邻、最右格没有右邻,这两侧得当成空的看——[0,0,1] 里最左那个 0 若不把左边界当空,就会被判成种不了、白白少算一朵。种下花后也得把这格真的置 1,忘了改,下一格看左邻时还当它空着,容易把两朵种到一起。至于 n=0,压根不用种、直接返回 true;单格花坛 [0] 反而能种一朵,别被长度短唬住。
▶ 动画逐步走查(共 16 步)——想跟着动画一帧帧对照就展开
- 3记住这条「空格 + 左右邻居都空(或在边界)就立刻种」,下面每一帧都在套它。
- 4这是初始花坛,绿底之外的 1 是一开始就种好的花。我们要从最左格开始,逐格判断「这里能不能补种一朵」。
- 5位置 0 是空的,左邻是边界(当作空)、右邻也空 → 立刻种下一朵(这格变 1、染绿)。已种 1 朵。
- 6位置 1 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 1 朵。
- 7位置 2 虽然空,但右邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 1 朵。
- 8位置 3 本来就有花(1),跳过,继续看下一格。已种 1 朵。
- 9位置 4 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 1 朵。
- 10位置 5 是空的,左邻也空、右邻也空 → 立刻种下一朵(这格变 1、染绿)。已种 2 朵。
- 11位置 6 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 2 朵。
- 12位置 7 虽然空,但右邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 2 朵。
- 13位置 8 本来就有花(1),跳过,继续看下一格。已种 2 朵。
- 14位置 9 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 2 朵。
- 15位置 10 是空的,左邻也空、右邻也空 → 立刻种下一朵(这格变 1、染绿)。已种 3 朵。
- 16位置 11 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 3 朵。
- 17位置 12 是空的,左邻空、右邻是边界(当作空)→ 立刻种下一朵(这格变 1、染绿)。已种 4 朵。
- 18扫到头了。绿色高亮的就是我们新种下的 4 朵花。4 ≥ 目标 3,所以答案是 true(种得下)。从左到右只扫一遍,O(n)。
⚠️ 容易写错的地方
✗ 错:忘了边界当作空
✓ 对:i==0 时没有左邻、i==m-1 时没有右邻,那一侧要视为空
不特判边界会漏掉「最左/最右能种」的情况,少算
✗ 错:判断后忘了真的种下(改数组)
✓ 对:种花后必须把 flowerbed[i] 置 1
不置 1,下一格判断左邻时会以为这里还空,可能种成相邻、违规
✗ 错:用 n>0 之类提前返回但逻辑写错
✓ 对:稳妥做法:扫完整数组累加 count,最后比 count>=n
能种就种、最后统一比较,最不容易错
完整代码(Python / C++ / Java)
Python
def canPlaceFlowers(flowerbed, n):
count = 0
m = len(flowerbed)
for i in range(m):
if flowerbed[i] == 0: # 当前格是空的
left = (i == 0) or flowerbed[i-1] == 0
right = (i == m - 1) or flowerbed[i+1] == 0
if left and right: # 左右都空(或在边界)
flowerbed[i] = 1 # 种一朵
count += 1
return count >= n # 够不够 n 朵C++
bool canPlaceFlowers(vector<int>& bed, int n){
int count = 0, m = bed.size();
for(int i = 0; i < m; i++){
if(bed[i] == 0){ // 当前格是空的
bool left = (i == 0) || bed[i-1] == 0;
bool right = (i == m - 1) || bed[i+1] == 0;
if(left && right){ // 左右都空(或边界)
bed[i] = 1; // 种一朵
count++;
}
}
}
return count >= n;
}Java
class Solution {
public boolean canPlaceFlowers(int[] bed, int n) {
int count = 0, m = bed.length;
for (int i = 0; i < m; i++) {
if (bed[i] == 0) { // 当前格是空的
boolean left = (i == 0) || bed[i - 1] == 0;
boolean right = (i == m - 1) || bed[i + 1] == 0;
if (left && right) { // 左右都空(或在边界)
bed[i] = 1; // 种一朵
count++;
}
}
}
return count >= n;
}
}复杂度
时间
O(n)
从左到右只遍历花坛一遍,每格做常数次比较
空间
O(1)
只用一个计数器(原地在花坛上改 0→1,不额外开空间)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 种花问题 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
不修改原数组,用一个变量记住前一格是不是花,能做吗?+
能。维护一个「上一格有没有花」的标记,配合当前格和下一格来判断,就不用真的去改 flowerbed。省了写数组这一步、逻辑完全等价。不过直接在数组上把种下的格子置 1 更直观,边界也少绕弯,面试里把「边界当空」这条讲清楚就行。
[0,0,0] 三个连续空格,为什么只能种两朵?+
从左扫:位置 0 左边是边界(当空)、右边是 0,种下,位置 0 变 1;位置 1 左边现在是花,跳过;位置 2 左边是 0、右边是边界,种下。两头各落一朵、中间被两边挡住,正好 2 朵。连续空格就是隔一个种一个,中间那些被相邻约束吃掉了。
n 很大或花坛很长,会不会超时?+
不会。从左到右只扫一遍,每格做几次常数比较,时间 O(n),n 是花坛长度;只用一个计数器、原地在数组上把 0 改成 1,空间 O(1)。就算 n 给得很大,也只是最后 count 比不过它、返回 false,扫描本身的开销不受影响。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 种花问题 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。