leetcode
leetcode 501 ~ 550
种花问题

种花问题

难度:

标签:

题目描述

代码结果

运行时间: 22 ms, 内存: 16.3 MB


/*
 * 思路:
 * 使用 Java Stream API 来实现相同的逻辑。由于 Stream API 不直接修改数组,我们需要映射成一个新数组。 
 * 然后使用相同的规则检查可以种花的地块。
 */
import java.util.stream.IntStream;
 
public class FlowerbedStream {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int count = (int) IntStream.range(0, flowerbed.length)
            .filter(i -> flowerbed[i] == 0 && (i == 0 || flowerbed[i - 1] == 0) && (i == flowerbed.length - 1 || flowerbed[i + 1] == 0))
            .peek(i -> flowerbed[i] = 1)
            .count();
        return count >= n;
    }
}

解释

方法:

这个题解采用了一次遍历的贪心策略。通过遍历花坛,统计当前位置左右两侧连续0的个数,如果个数大于等于2,就可以种下一朵花。同时用一个变量 prev 记录上一朵已种花的位置,用于计算当前位置与上一朵花之间的间隔。最后再根据最后一朵花的位置,计算剩余的空位数量,更新可种花的总数 count。如果 count 大于等于 n,说明可以种下 n 朵花,返回 True,否则返回 False。

时间复杂度:

O(m)

空间复杂度:

O(1)

代码细节讲解

🦆
如何处理数组两端的边界情况,特别是当花坛开头和结束的地块都是0时?
对于花坛两端的处理,题解采用以下策略:如果整个花坛的开头没有花(即`prev`初始化为-1),则可以将整个开头连续的0视为一个特殊区域,其可种花的数量由`(i // 2)`计算,其中`i`为第一个遇到的1的位置,或者如果没有1则为花坛的长度。对于花坛的末尾,如果最后一个位置是0,则从最后一个1之后的位置到花坛末尾的连续0也是一个特殊区域,计算其可种花的数量通过`(m - prev - 1) // 2`实现,其中`m`是花坛的长度,`prev`是最后一个1的位置。这样的处理确保了花坛两端的0都被充分利用。
🦆
在代码中,`prev` 初始化为-1,这样的设定是否会影响计算第一个位置(即索引为0)时可种花的数量?
初始化`prev`为-1是为了处理花坛开头是0的情况。这样的设定意味着在花坛的第一个元素之前假想一个位置-1处有一个1,这使得第一个0到第一个1之间的距离正确计算。如果花坛的第一个位置是0并且之后连续有多个0,那么这些0在没有任何前面的1阻碍的情况下,可以按照`(i // 2)`的方法计算可种花的数量。因此,这种初始化方式是合理且有助于边界情况的处理。
🦆
题解中提到的‘左右两侧连续0的个数’如何准确计算,尤其是在花坛中间部分的0?
对于花坛中间部分的0,准确计算左右两侧连续0的个数依赖于记录上一朵花的位置`prev`。当遇到一个1时,`prev`会更新为当前1的位置。计算任何两个1之间的0的数量(即`i - prev - 2`,其中`i`是当前1的位置),通过这个数量除以2得到这段区域内可以种植的花的数量。这种方法确保了只有当两个1之间至少有一个间隔(即2个0)时,才会种植一朵花,因此可以正确地处理中间0的情况。
🦆
如果在遍历过程中已经可以种下所需数量的花,为什么还需要继续遍历直到数组末尾?
题解中的代码实际上在满足种花数量要求时会提前终止遍历并返回True,这是通过`if count >= n`这个条件检查实现的。这种提前终止遍历的策略是高效的,因为一旦我们已经种下了所需的花的数量,就没有必要继续检查剩余的部分。这样做可以节省时间,使算法效率更高。

相关问题

提莫攻击

在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。

当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。

正式地讲,提莫在 t 发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 tt + duration - 1)处于中毒状态。如果提莫在中毒影响结束 再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。

给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration

返回艾希处于中毒状态的 秒数。

 

示例 1:

输入:timeSeries = [1,4], duration = 2
输出:4
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。
艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。

示例 2:

输入:timeSeries = [1,2], duration = 2
输出:3
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 2 秒,提莫再次攻击艾希,并重置中毒计时器,艾希中毒状态需要持续 2 秒,即第 2 秒和第 3 秒。
艾希在第 1、2、3 秒处于中毒状态,所以总中毒秒数是 3 。

 

提示:

  • 1 <= timeSeries.length <= 104
  • 0 <= timeSeries[i], duration <= 107
  • timeSeries非递减 顺序排列

小行星碰撞

给定一个整数数组 asteroids,表示在同一行的小行星。

对于数组中的每一个元素,其绝对值表示小行星的大小,正负表示小行星的移动方向(正表示向右移动,负表示向左移动)。每一颗小行星以相同的速度移动。

找出碰撞后剩下的所有小行星。碰撞规则:两个小行星相互碰撞,较小的小行星会爆炸。如果两颗小行星大小相同,则两颗小行星都会爆炸。两颗移动方向相同的小行星,永远不会发生碰撞。

 

示例 1:

输入:asteroids = [5,10,-5]
输出:[5,10]
解释:10 和 -5 碰撞后只剩下 10 。 5 和 10 永远不会发生碰撞。

示例 2:

输入:asteroids = [8,-8]
输出:[]
解释:8 和 -8 碰撞后,两者都发生爆炸。

示例 3:

输入:asteroids = [10,2,-5]
输出:[10]
解释:2 和 -5 发生碰撞后剩下 -5 。10 和 -5 发生碰撞后剩下 10 。

 

提示:

  • 2 <= asteroids.length <= 104
  • -1000 <= asteroids[i] <= 1000
  • asteroids[i] != 0