201 lines
8.8 KiB
YAML
201 lines
8.8 KiB
YAML
title: Can Place Flowers
|
|
slug: can-place-flowers
|
|
difficulty: easy
|
|
leetcode_id: 605
|
|
leetcode_url: https://leetcode.com/problems/can-place-flowers/
|
|
categories:
|
|
- arrays
|
|
patterns:
|
|
- slug: greedy
|
|
is_optimal: true
|
|
|
|
function_signature: "def can_place_flowers(flowerbed: list[int], n: int) -> bool:"
|
|
|
|
test_cases:
|
|
visible:
|
|
- input: { flowerbed: [1, 0, 0, 0, 1], n: 1 }
|
|
expected: true
|
|
- input: { flowerbed: [1, 0, 0, 0, 1], n: 2 }
|
|
expected: false
|
|
hidden:
|
|
- input: { flowerbed: [0], n: 1 }
|
|
expected: true
|
|
- input: { flowerbed: [1], n: 0 }
|
|
expected: true
|
|
- input: { flowerbed: [0, 0, 0, 0, 0], n: 3 }
|
|
expected: true
|
|
- input: { flowerbed: [0, 0, 0, 0, 0], n: 4 }
|
|
expected: false
|
|
- input: { flowerbed: [1, 0, 0, 0, 0, 1], n: 1 }
|
|
expected: true
|
|
- input: { flowerbed: [0, 0, 1, 0, 0], n: 2 }
|
|
expected: true
|
|
- input: { flowerbed: [1, 0, 1, 0, 1], n: 1 }
|
|
expected: false
|
|
|
|
description: |
|
|
You have a long flowerbed in which some of the plots are planted, and some are not. However, flowers cannot be planted in **adjacent** plots.
|
|
|
|
Given an integer array `flowerbed` containing `0`'s and `1`'s, where `0` means empty and `1` means not empty, and an integer `n`, return `true` *if* `n` *new flowers can be planted in the flowerbed without violating the no-adjacent-flowers rule and* `false` *otherwise*.
|
|
|
|
constraints: |
|
|
- `1 <= flowerbed.length <= 2 * 10^4`
|
|
- `flowerbed[i]` is `0` or `1`
|
|
- There are no two adjacent flowers in `flowerbed`
|
|
- `0 <= n <= flowerbed.length`
|
|
|
|
examples:
|
|
- input: "flowerbed = [1,0,0,0,1], n = 1"
|
|
output: "true"
|
|
explanation: "We can plant one flower at index 2. The flowerbed becomes [1,0,1,0,1], which satisfies the no-adjacent-flowers rule."
|
|
- input: "flowerbed = [1,0,0,0,1], n = 2"
|
|
output: "false"
|
|
explanation: "There is only one valid spot (index 2) to plant a flower. We cannot plant 2 flowers without violating the adjacency rule."
|
|
|
|
explanation:
|
|
intuition: |
|
|
Imagine walking through a garden path where each plot is either empty (`0`) or has a flower (`1`). Your task is to plant as many flowers as possible without placing two flowers next to each other.
|
|
|
|
The key insight is that we can make a **greedy decision** at each empty plot: if we *can* plant a flower here (no adjacent flowers), we *should* plant it immediately. There's never a benefit to "saving" a spot for later — planting now can only help us, never hurt us.
|
|
|
|
Think of it like this: you're walking left to right. At each empty plot, you check three things:
|
|
- Is the plot to my left empty (or am I at the start)?
|
|
- Is the current plot empty?
|
|
- Is the plot to my right empty (or am I at the end)?
|
|
|
|
If all three conditions are true, plant a flower and move on. By greedily planting whenever possible, you guarantee the maximum number of flowers.
|
|
|
|
approach: |
|
|
We solve this using a **Single Pass Greedy Approach**:
|
|
|
|
**Step 1: Initialise a counter**
|
|
|
|
- `count`: Set to `0` to track how many flowers we've planted
|
|
|
|
|
|
|
|
**Step 2: Iterate through the flowerbed**
|
|
|
|
- For each position `i`, check if we can plant a flower:
|
|
- Current plot must be empty: `flowerbed[i] == 0`
|
|
- Left neighbour must be empty or out of bounds: `i == 0` or `flowerbed[i-1] == 0`
|
|
- Right neighbour must be empty or out of bounds: `i == len(flowerbed) - 1` or `flowerbed[i+1] == 0`
|
|
- If all conditions are met, plant the flower:
|
|
- Set `flowerbed[i] = 1` (this prevents planting at `i+1`)
|
|
- Increment `count`
|
|
|
|
|
|
|
|
**Step 3: Early termination (optimisation)**
|
|
|
|
- If `count >= n` at any point, we can return `True` immediately
|
|
- No need to continue checking once we've planted enough flowers
|
|
|
|
|
|
|
|
**Step 4: Return the result**
|
|
|
|
- After the loop, return `count >= n`
|
|
|
|
|
|
|
|
This greedy approach works because planting a flower at the earliest valid position never prevents us from achieving the maximum count — it only restricts the immediately adjacent plot, which wouldn't have been valid anyway.
|
|
|
|
common_pitfalls:
|
|
- title: Forgetting Boundary Conditions
|
|
description: |
|
|
The first and last plots only have one neighbour to check, not two.
|
|
|
|
For position `0`, there is no left neighbour — treat it as empty. Similarly, for the last position, there is no right neighbour.
|
|
|
|
Failing to handle boundaries leads to index-out-of-bounds errors or incorrect results for flowerbeds like `[0,0,1]` where the first plot is plantable.
|
|
wrong_approach: "Always checking both neighbours without boundary checks"
|
|
correct_approach: "Use `i == 0` or `i == len-1` to handle edge positions"
|
|
|
|
- title: Not Marking Planted Flowers
|
|
description: |
|
|
After deciding to plant at position `i`, you must update `flowerbed[i] = 1`.
|
|
|
|
If you only increment a counter without modifying the array, the next iteration will incorrectly think position `i+1` has an empty left neighbour. This leads to planting adjacent flowers.
|
|
|
|
Example: In `[0,0,0]`, if you plant at index `0` but don't mark it, you'll also "plant" at index `1`, violating the adjacency rule.
|
|
wrong_approach: "Only counting without modifying the array"
|
|
correct_approach: "Set flowerbed[i] = 1 after planting"
|
|
|
|
- title: Checking n > 0 Instead of count >= n
|
|
description: |
|
|
When `n = 0`, the answer should always be `True` — you don't need to plant any flowers.
|
|
|
|
Some implementations decrement `n` each time they plant, then check `n <= 0`. This works, but be careful with the initial check: if `n == 0` from the start, return `True` immediately or ensure your loop handles it correctly.
|
|
|
|
key_takeaways:
|
|
- "**Greedy validity**: When a locally optimal choice (plant now) never hurts the global solution, greedy works"
|
|
- "**In-place modification**: Updating the input array lets us track state without extra space"
|
|
- "**Boundary handling**: Always consider edge cases at array boundaries — they often have special rules"
|
|
- "**Early termination**: Once you've achieved the goal (`count >= n`), stop early for efficiency"
|
|
|
|
time_complexity: "O(n). We traverse the flowerbed array once, where `n` is the length of the array."
|
|
space_complexity: "O(1). We modify the input array in-place and use only a constant amount of extra space for the counter."
|
|
|
|
solutions:
|
|
- approach_name: Single Pass Greedy
|
|
is_optimal: true
|
|
code: |
|
|
def can_place_flowers(flowerbed: list[int], n: int) -> bool:
|
|
count = 0
|
|
length = len(flowerbed)
|
|
|
|
for i in range(length):
|
|
# Check if current plot is empty
|
|
if flowerbed[i] == 0:
|
|
# Check left neighbour (or start of array)
|
|
left_empty = (i == 0) or (flowerbed[i - 1] == 0)
|
|
# Check right neighbour (or end of array)
|
|
right_empty = (i == length - 1) or (flowerbed[i + 1] == 0)
|
|
|
|
# If both neighbours are empty, plant here
|
|
if left_empty and right_empty:
|
|
flowerbed[i] = 1 # Mark as planted
|
|
count += 1
|
|
|
|
# Early exit if we've planted enough
|
|
if count >= n:
|
|
return True
|
|
|
|
return count >= n
|
|
explanation: |
|
|
**Time Complexity:** O(n) — Single pass through the flowerbed.
|
|
|
|
**Space Complexity:** O(1) — We modify the input array in-place and use only a counter variable.
|
|
|
|
We iterate through each plot once. When we find a valid spot (current empty, left empty or boundary, right empty or boundary), we plant and mark it. The modification prevents consecutive plantings. Early termination provides a small optimisation when `n` is small.
|
|
|
|
- approach_name: Count Consecutive Zeros
|
|
is_optimal: false
|
|
code: |
|
|
def can_place_flowers(flowerbed: list[int], n: int) -> bool:
|
|
# Pad with zeros for easier boundary handling
|
|
padded = [0] + flowerbed + [0]
|
|
count = 0
|
|
zeros = 0
|
|
|
|
for plot in padded:
|
|
if plot == 0:
|
|
zeros += 1
|
|
else:
|
|
# Calculate flowers that fit in this gap
|
|
# For k consecutive zeros, we can fit (k-1)//2 flowers
|
|
count += (zeros - 1) // 2
|
|
zeros = 0
|
|
|
|
# Don't forget the trailing zeros
|
|
count += (zeros - 1) // 2
|
|
|
|
return count >= n
|
|
explanation: |
|
|
**Time Complexity:** O(n) — Single pass through the padded array.
|
|
|
|
**Space Complexity:** O(n) — We create a new padded array.
|
|
|
|
This approach counts consecutive zeros between flowers. For `k` consecutive empty plots (including virtual padding), we can plant `(k-1) // 2` flowers. The padding simplifies boundary handling. While correct, this uses extra space compared to the in-place greedy approach.
|