题目链接:力扣605种花问题
题目描述:
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false 。
示例 1:
输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
示例 2:
输入:flowerbed = [1,0,0,0,1], n = 2
输出:false
题解:
采用贪心算法,寻找最多可以种植多少朵花,也可以转化为求能够种花的空地有多少,假设下标
i
,
j
i, j
i,j处种了花
(
j
−
i
≥
2
)
(j - i \ge2)
(j−i≥2),则
i
,
j
i,j
i,j之间的空地有
j
−
i
−
1
j-i-1
j−i−1个,又因为
[
i
,
j
]
[i,j]
[i,j]内与两花相邻的两个空地不能种花,因此区间
[
i
,
j
]
[i,j]
[i,j]内可以种花的空地有
j
−
i
−
3
j-i-3
j−i−3个。
令
q
=
j
−
i
−
3
q = j-i-3
q=j−i−3
- 当 q q q为奇数时,可以选择端点种花,中间依次间隔一位,则最多可种植 ( q + 1 ) / 2 (q + 1)/2 (q+1)/2朵花,例如 1 , 0 , 0 , 0 , 0 , 0 , 1 1,0,0,0,0,0,1 1,0,0,0,0,0,1,其中 i = 0 , j = 6 , q = 3 i=0,j=6,q=3 i=0,j=6,q=3,选择最中间三个空位种植花朵,即花坛变为 1 , 0 , 1 , 0 , 1 , 0 , 1 1,0,1,0,1,0,1 1,0,1,0,1,0,1
- 当 q q q为偶数时,最多可种植 q / 2 q/2 q/2朵花,例如 1 , 0 , 0 , 0 , 0 , 1 1,0,0,0,0,1 1,0,0,0,0,1, i = 0 , j = 5 , q = 2 i=0,j=5,q=2 i=0,j=5,q=2,选择最中间两个空位中的一个种植花朵,花坛变为 1 , 0 , 1 , 0 , 0 , 1 1,0,1,0,0,1 1,0,1,0,0,1
综上所述,可以定义
p
r
e
v
prev
prev和
i
i
i分别指向两个相邻的已种花的位置,令
p
r
e
v
=
−
1
prev = -1
prev=−1,
特殊情况:
- 当首次遍历flowerbed[i] == 1时,只有当 i ≥ 2 i\ge2 i≥2时,左边才能够种植花朵,此时 i i i左边的空位数为 i i i,能够种植花的空地为 i − 1 i-1 i−1;
- 当遍历到最后一朵花flowerbed[i]===1的时候, i i i右边的空地数为 l e n ( f l o w e r b e d ) − i − 1 len(flowerbed) - i - 1 len(flowerbed)−i−1,能够种花的空地数为 l e n ( f l o w e r b e d ) − i − 2 len(flowerbed) - i - 2 len(flowerbed)−i−2
中间部分相邻两朵花的计算由以上分析可得;
代码:
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
"""
count 为种植花的数目
prev指向前一个种植花的下标
"""
count , m ,prev = 0, len(flowerbed), -1
for i in range(m):
if flowerbed[i] == 1:
if prev < 0: #i为花坛最左边的一朵花
count += i // 2
else:
count += (i - prev - 1 - 2 + 1) // 2
prev = i
if prev < 0: #花坛中不存在花
count = (m + 1) //2
else: #prev指向花坛中最右边的一朵花
count += (m - prev - 1) // 2
return count >= n