题目描述
思路解析
一句话答案: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] 反而能种一朵,别被长度短唬住。
▶ 动画逐步走查(文字版)——想跟着上方动画一帧帧对照就展开
记住这条「空格 + 左右邻居都空(或在边界)就立刻种」,下面每一帧都在套它。
这是初始花坛,绿底之外的 1 是一开始就种好的花。我们要从最左格开始,逐格判断「这里能不能补种一朵」。
位置 0 是空的,左邻是边界(当作空)、右邻也空 → 立刻种下一朵(这格变 1、染绿)。已种 1 朵。
位置 1 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 1 朵。
位置 2 虽然空,但右邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 1 朵。
位置 3 本来就有花(1),跳过,继续看下一格。已种 1 朵。
位置 4 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 1 朵。
位置 5 是空的,左邻也空、右邻也空 → 立刻种下一朵(这格变 1、染绿)。已种 2 朵。
位置 6 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 2 朵。
位置 7 虽然空,但右邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 2 朵。
位置 8 本来就有花(1),跳过,继续看下一格。已种 2 朵。
位置 9 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 2 朵。
位置 10 是空的,左邻也空、右邻也空 → 立刻种下一朵(这格变 1、染绿)。已种 3 朵。
位置 11 虽然空,但左邻有花,种下去就会和邻居相邻,违规 → 不能种,跳过。已种 3 朵。
位置 12 是空的,左邻空、右邻是边界(当作空)→ 立刻种下一朵(这格变 1、染绿)。已种 4 朵。
扫到头了。绿色高亮的就是我们新种下的 4 朵花。4 ≥ 目标 3,所以答案是 true(种得下)。从左到右只扫一遍,O(n)。
边界先想清:单格、全空、n=0、相邻挤占都要能算对。
两个高频追问,核心是贪心选择的最优性与实现技巧。
参考代码
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 朵复杂度
- 时间:O(n),从左到右只遍历花坛一遍,每格做常数次比较
- 空间:O(1),只用一个计数器(原地在花坛上改 0→1,不额外开空间)
易错点
面试追问把动画讲成自己的话
追问为什么「能种就立刻种(越靠左越好)」是最优的,不会错过更多机会?
追问能不能不真的修改数组,用变量记录前一格状态来做?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
柠檬水找零
LeetCode 860 · 简单 · 沿着 贪心套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题