种花问题
- https://leetcode.cn/problems/can-place-flowers/
描述
-
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
-
给你一个整数数组 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
提示:
- 1 <= flowerbed.length <= 2 * 10410^4104
- flowerbed[i] 为 0 或 1
- flowerbed 中不存在相邻的两朵花
- 0 <= n <= flowerbed.length
Typescript 版算法实现
1 )方案1:简单遍历
// 判断是否能在花坛中种植指定数量的花
function canPlaceFlowers(flowerbed: number[], n: number): boolean {
let cnt = 0; // 计数已经种植的花的数量
const m = flowerbed.length; // 花坛数组的长度
for (let i = 0; i < m; i++) {
// 当前位置左侧是否为空地
const isLeftEmpty = i === 0 || flowerbed[i - 1] === 0;
// 当前位置是否为空地
const isCurrentEmpty = flowerbed[i] === 0;
// 当前位置右侧是否为空地
const isRightEmpty = i === m - 1 || flowerbed[i + 1] === 0;
// 如果左侧、当前位置、右侧均为空地,则可以在当前位置种花
if (isLeftEmpty && isCurrentEmpty && isRightEmpty) {
flowerbed[i] = 1; // 在当前位置种花
cnt++; // 更新已经种植的花的数量
}
}
// 判断是否可以完成种植
return cnt >= n;
}
- 主要思路是判断在给定的花坛状态中是否能够种植指定数量的花,满足以下条件:
- 在花坛中的每个位置,如果其左侧相邻位置和右侧相邻位置都是 0,表示该位置可以种花。
- 遍历花坛数组,检查每个位置是否满足上述条件,如果满足,则种植花,并累计已经种植的花的数量。
- 最后,比较已经种植的花的数量与目标数量,确定是否可以完成种植。
- 具体实现步骤:
- 遍历花坛数组中的每个位置。
- 对于每个位置,检查其左侧相邻位置和右侧相邻位置的状态,确定是否可以在当前位置种植花。
- 如果可以种植花,则将当前位置标记为已经种植,并将已经种植的花的数量加一。
- 遍历完整个花坛后,比较已经种植的花的数量与目标数量,确定是否可以完成种植。
2 )方案 2:基于规则的逐步判断
function canPlaceFlowers(flowerbed: number[], n: number): boolean {
// 计数
let count = 0
// 在这里对数组进行扩展来方便编程,最后一块地能不能种只取决于前面的是不是1,所以默认最后一块地的右侧是0
flowerbed.push(0)
for (let i = 0, len = flowerbed.length - 1; i < len; i++) {
// 当前是非零的情况,直接跳过
if (flowerbed[i] !== 0) {
continue
}
// 开始边界的处理
if (i === 0 && flowerbed[1] === 0) {
count++
i++
} else if (flowerbed[i - 1] === 0 && flowerbed[i + 1] === 0) {
// 这种情况是正常情况,当前左右都是0,则可种树
count++
i++
}
// 结束边界无需处理,因为数组在最后扩展了一个0,上述正常情况已经包含了 无
}
return count >= n
}
- 哪些情况下可以种花,简化模型
- 这里的地就是指 1或0,1是一块地,0也是一块地
- 我们需要放1,能放1的地方是左边和右边都是0,并且当前位置是0
- 匹配完成后,我们要主动跳过当前匹配,也就是跳2个位置
- 体现在手动 i++以及for循环一次后自带的一个i++
3 )方案3:基于规则的逐步判断 + 滑动窗口
// 判断是否能在花坛中种植指定数量的花
function canPlaceFlowers(flowerbed: number[], n: number): boolean {
// 左边界,初始为虚拟节点
let l = -1;
// 右边界
let r = 0;
// 遍历花坛数组
while (r <= flowerbed.length) {
// 获取右边界的值,若超出范围则为虚拟节点值
const rv = r === flowerbed.length ? 0 : flowerbed[r];
// 右边界右移
r++;
// 如果右边界是已种植的花,则更新左边界为右边界
if (rv === 1) {
l = r;
}
// 如果两边界相隔3个位置,则可以在中间位置种植一朵花
if (r - l === 3) {
// 减去需要种植的花的数量
n--;
// 更新左边界为下一个位置
l += 2;
}
}
// 若需要种植的花的数量小于等于0,则表示可以完成种植
return n <= 0;
}
-
初始化边界
- 将左边界
l初始化为虚拟节点(-1),表示初始时还没有遇到任何已种植的花。 - 将右边界
r初始化为花坛数组的起始位置(0)。
- 将左边界
-
遍历花坛数组
- 从左到右遍历花坛数组,确保在数组范围内。
-
更新右边界和检查已种植的花
- 获取右边界
r的值rv,如果超出花坛数组范围,则将其设为虚拟节点值 0。 - 右边界
r向右移动。
- 获取右边界
-
更新左边界
- 如果右边界的值
rv是已种植的花(值为 1),则将左边界l更新为当前右边界r。
- 如果右边界的值
-
判断是否可以在中间位置种植花
- 如果右边界与左边界相隔 3 个位置(
r - l === 3),表示在这两朵已种植的花之间有足够的空地可以种植新花。 - 将需要种植的花的数量
n减一。 - 将左边界
l更新为下一个位置(l += 2),以继续检查下一个区间。
- 如果右边界与左边界相隔 3 个位置(
-
判断是否完成种植
- 当所有花坛遍历完毕后,检查剩余需要种植的花的数量
n是否小于等于 0。 - 如果小于等于 0,则表示可以完成种植,返回
true;否则,表示不能完成种植,返回false。
- 当所有花坛遍历完毕后,检查剩余需要种植的花的数量
-
通过维护左右边界和逐步判断每两朵已种植的花之间的空地情况
-
算法能够有效地判断是否能够在花坛中种植指定数量的花。
Python3 版算法实现
1 )方案1:简单遍历
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
cnt = 0 # 计数已经种植的花的数量
m = len(flowerbed) # 花坛数组的长度
for i in range(m):
# 当前位置左侧是否为空地
is_left_empty = i == 0 or flowerbed[i - 1] == 0
# 当前位置是否为空地
is_current_empty = flowerbed[i] == 0
# 当前位置右侧是否为空地
is_right_empty = i == m - 1 or flowerbed[i + 1] == 0
# 如果左侧、当前位置、右侧均为空地,则可以在当前位置种花
if is_left_empty and is_current_empty and is_right_empty:
flowerbed[i] = 1 # 在当前位置种花
cnt += 1 # 更新已经种植的花的数量
# 判断是否可以完成种植
return cnt >= n
2 )方案 2:基于规则的逐步判断
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
# 计数
count = 0
# 在这里对数组进行扩展来方便编程,最后一块地能不能种只取决于前面的是不是1,所以默认最后一块地的右侧是0
flowerbed.append(0)
i = 0
while i < len(flowerbed) - 1:
# 当前是非零的情况,直接跳过
if flowerbed[i] != 0:
i += 1
continue
# 开始边界的处理
if i == 0 and flowerbed[1] == 0:
count += 1
i += 1
elif flowerbed[i - 1] == 0 and flowerbed[i + 1] == 0:
# 这种情况是正常情况,当前左右都是0,则可种树
count += 1
i += 1
# 结束边界无需处理,因为数组在最后扩展了一个0,上述正常情况已经包含了
i += 1
return count >= n
3 )方案3:基于规则的逐步判断 + 滑动窗口
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
# 左边界,初始为虚拟节点
l = -1
# 右边界
r = 0
# 遍历花坛数组
while r <= len(flowerbed):
# 获取右边界的值,若超出范围则为虚拟节点值
rv = flowerbed[r] if r < len(flowerbed) else 0
# 右边界右移
r += 1
# 如果右边界是已种植的花,则更新左边界为右边界
if rv == 1:
l = r
# 如果两边界相隔3个位置,则可以在中间位置种植一朵花
if r - l == 3:
# 减去需要种植的花的数量
n -= 1
# 更新左边界为下一个位置
l += 2
# 若需要种植的花的数量小于等于0,则表示可以完成种植
return n <= 0
Golang 版算法实现
1 )方案1:简单遍历
func canPlaceFlowers(flowerbed []int, n int) bool {
cnt := 0
m := len(flowerbed)
for i := 0; i < m; i++ {
// 当前位置左侧是否为空地
isLeftEmpty := i == 0 || flowerbed[i-1] == 0
// 当前位置是否为空地
isCurrentEmpty := flowerbed[i] == 0
// 当前位置右侧是否为空地
isRightEmpty := i == m-1 || flowerbed[i+1] == 0
// 如果左侧、当前位置、右侧均为空地,则可以在当前位置种花
if isLeftEmpty && isCurrentEmpty && isRightEmpty {
flowerbed[i] = 1
cnt++
}
}
// 判断是否可以完成种植
return cnt >= n
}
2 )方案 2:基于规则的逐步判断
func canPlaceFlowers(flowerbed []int, n int) bool {
// 计数
count := 0
// 在这里对数组进行扩展来方便编程,最后一块地能不能种只取决于前面的是不是1,所以默认最后一块地的右侧是0
flowerbed = append(flowerbed, 0)
i := 0
for i < len(flowerbed)-1 {
// 当前是非零的情况,直接跳过
if flowerbed[i] != 0 {
i++
continue
}
// 开始边界的处理
if i == 0 && flowerbed[1] == 0 {
count++
i += 2 // 修改这里的索引增量为2
} else if i > 0 && flowerbed[i-1] == 0 && flowerbed[i+1] == 0 { // 修改这里的条件,确保索引不为负数
// 这种情况是正常情况,当前左右都是0,则可种树
count++
i += 2 // 修改这里的索引增量为2
} else {
i++
}
// 结束边界无需处理,因为数组在最后扩展了一个0,上述正常情况已经包含了
}
return count >= n
}
3 )方案3:基于规则的逐步判断 + 滑动窗口
// 判断是否能在花坛中种植指定数量的花
func canPlaceFlowers(flowerbed []int, n int) bool {
// 左边界,初始为虚拟节点
l := -1
// 右边界
r := 0
// 遍历花坛数组
for r <= len(flowerbed) {
// 获取右边界的值,若超出范围则为虚拟节点值
var rv int
if r == len(flowerbed) {
rv = 0
} else {
rv = flowerbed[r]
}
// 右边界右移
r++
// 如果右边界是已种植的花,则更新左边界为右边界
if rv == 1 {
l = r
}
// 如果两边界相隔3个位置,则可以在中间位置种植一朵花
if r-l == 3 {
// 减去需要种植的花的数量
n--
// 更新左边界为下一个位置
l += 2
}
}
// 若需要种植的花的数量小于等于0,则表示可以完成种植
return n <= 0
}
650



被折叠的 条评论
为什么被折叠?



