LeetCode 1465 - Maximum Area of a Piece of Cake After Horizontal and Vertical Cuts
This problem gives us a rectangular cake with height h and width w. We are also given two arrays: - horizontalCuts, whic
Difficulty: 🟡 Medium
Topics: Array, Greedy, Sorting
Solution
LeetCode 1465 - Maximum Area of a Piece of Cake After Horizontal and Vertical Cuts
Problem Understanding
This problem gives us a rectangular cake with height h and width w. We are also given two arrays:
horizontalCuts, which contains the positions of horizontal cuts measured from the top edgeverticalCuts, which contains the positions of vertical cuts measured from the left edge
Every cut slices completely across the cake in its direction. After performing all cuts, the cake is divided into multiple rectangular pieces. The task is to determine the area of the largest resulting piece.
The important observation is that every piece is rectangular. Its height is determined by the distance between two consecutive horizontal boundaries, and its width is determined by the distance between two consecutive vertical boundaries.
The output should be the maximum possible area among all resulting pieces. Since the area can become extremely large, we must return the result modulo 10^9 + 7.
The constraints are important:
handwcan be as large as10^9- The number of cuts can be as large as
10^5
These limits immediately tell us that we cannot simulate every resulting rectangle explicitly. A naive approach that examines every possible piece would be far too slow.
The problem also guarantees:
- All cuts are distinct
- Every cut lies strictly inside the cake
- There is at least one cut in each direction
Several edge cases are important:
- The largest piece may lie against the cake boundary, so we must consider the distance from the edge to the nearest cut.
- The cuts may not be sorted.
- The largest horizontal gap and largest vertical gap may occur at different positions.
- The multiplication may overflow normal 32-bit integers, especially in Go.
Approaches
Brute Force Approach
A brute force solution would first determine every horizontal segment and every vertical segment, then generate every possible rectangle formed by combining them.
For example:
- If there are
mhorizontal segments - And
nvertical segments
Then there are m * n cake pieces.
We could compute each rectangle area individually and track the maximum.
This works because every resulting piece is formed by one horizontal interval and one vertical interval.
However, this approach is unnecessarily expensive. The number of segments can reach 10^5, which means the number of rectangles could approach 10^10. That is impossible to process within time limits.
Optimal Approach
The key insight is that the maximum rectangle area is simply:
- the maximum horizontal gap
- multiplied by the maximum vertical gap
We do not need to examine every rectangle individually.
Why does this work?
Every piece's area is:
piece_area = horizontal_gap * vertical_gap
To maximize the product, we independently maximize:
- the height of a segment
- the width of a segment
So the problem reduces to:
- Sort the horizontal cuts
- Find the largest distance between consecutive horizontal boundaries
- Sort the vertical cuts
- Find the largest distance between consecutive vertical boundaries
- Multiply the two maximum gaps
The boundaries of the cake itself must also be included:
0andhfor horizontal cuts0andwfor vertical cuts
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(m * n) | O(1) | Checks every resulting rectangle |
| Optimal | O(m log m + n log n) | O(1) or O(log n) depending on sorting | Finds only the largest gaps |
Algorithm Walkthrough
- Sort the
horizontalCutsarray so consecutive cuts can be examined in order. - Compute the maximum horizontal gap.
First, consider the gap between the top edge (0) and the first cut. Then examine every consecutive pair of cuts. Finally, consider the gap between the last cut and the bottom edge (h).
3. Sort the verticalCuts array for the same reason.
4. Compute the maximum vertical gap.
Again, include the left edge (0) and right edge (w) when calculating distances.
5. Multiply the largest horizontal gap by the largest vertical gap.
This gives the largest possible rectangular piece.
6. Return the result modulo 10^9 + 7.
Why it works
Every final cake piece is formed by exactly one horizontal interval and one vertical interval. The area of a piece is the product of those two dimensions.
Because multiplication is monotonic for positive values, the largest area must come from:
- the largest horizontal interval
- and the largest vertical interval
No other combination can produce a larger area.
Python Solution
from typing import List
class Solution:
def maxArea(self, h: int, w: int, horizontalCuts: List[int], verticalCuts: List[int]) -> int:
MOD = 10**9 + 7
horizontalCuts.sort()
verticalCuts.sort()
max_horizontal_gap = horizontalCuts[0]
for i in range(1, len(horizontalCuts)):
gap = horizontalCuts[i] - horizontalCuts[i - 1]
max_horizontal_gap = max(max_horizontal_gap, gap)
max_horizontal_gap = max(
max_horizontal_gap,
h - horizontalCuts[-1]
)
max_vertical_gap = verticalCuts[0]
for i in range(1, len(verticalCuts)):
gap = verticalCuts[i] - verticalCuts[i - 1]
max_vertical_gap = max(max_vertical_gap, gap)
max_vertical_gap = max(
max_vertical_gap,
w - verticalCuts[-1]
)
return (max_horizontal_gap * max_vertical_gap) % MOD
The implementation begins by sorting both cut arrays. Sorting is necessary because the largest gap can only be identified correctly when cuts are processed in order.
The code then computes the largest horizontal interval. It first considers the distance from the top edge to the first cut. After that, it checks all consecutive gaps between cuts. Finally, it checks the distance from the last cut to the bottom edge.
The same logic is repeated for vertical cuts.
Once both maximum gaps are known, the algorithm multiplies them together to obtain the largest area. The modulo operation is applied at the end to satisfy the problem requirement.
Go Solution
package main
import "sort"
func maxArea(h int, w int, horizontalCuts []int, verticalCuts []int) int {
const MOD int64 = 1_000_000_007
sort.Ints(horizontalCuts)
sort.Ints(verticalCuts)
maxHorizontalGap := horizontalCuts[0]
for i := 1; i < len(horizontalCuts); i++ {
gap := horizontalCuts[i] - horizontalCuts[i-1]
if gap > maxHorizontalGap {
maxHorizontalGap = gap
}
}
if h-horizontalCuts[len(horizontalCuts)-1] > maxHorizontalGap {
maxHorizontalGap = h - horizontalCuts[len(horizontalCuts)-1]
}
maxVerticalGap := verticalCuts[0]
for i := 1; i < len(verticalCuts); i++ {
gap := verticalCuts[i] - verticalCuts[i-1]
if gap > maxVerticalGap {
maxVerticalGap = gap
}
}
if w-verticalCuts[len(verticalCuts)-1] > maxVerticalGap {
maxVerticalGap = w - verticalCuts[len(verticalCuts)-1]
}
area := (int64(maxHorizontalGap) * int64(maxVerticalGap)) % MOD
return int(area)
}
The Go implementation follows the same algorithmic structure as the Python solution.
The main difference is integer overflow handling. Since the product of two gaps can exceed the range of a 32-bit integer, the multiplication is performed using int64.
Go also requires explicit sorting using sort.Ints.
Worked Examples
Example 1
h = 5
w = 4
horizontalCuts = [1, 2, 4]
verticalCuts = [1, 3]
Step 1: Sort the cuts
| Type | Sorted Cuts |
|---|---|
| Horizontal | [1, 2, 4] |
| Vertical | [1, 3] |
Step 2: Compute horizontal gaps
| Previous Boundary | Current Boundary | Gap |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 2 | 1 |
| 2 | 4 | 2 |
| 4 | 5 | 1 |
Maximum horizontal gap = 2
Step 3: Compute vertical gaps
| Previous Boundary | Current Boundary | Gap |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 3 | 2 |
| 3 | 4 | 1 |
Maximum vertical gap = 2
Step 4: Compute area
2 * 2 = 4
Final answer:
4
Example 2
h = 5
w = 4
horizontalCuts = [3, 1]
verticalCuts = [1]
Step 1: Sort the cuts
| Type | Sorted Cuts |
|---|---|
| Horizontal | [1, 3] |
| Vertical | [1] |
Step 2: Compute horizontal gaps
| Previous Boundary | Current Boundary | Gap |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 3 | 2 |
| 3 | 5 | 2 |
Maximum horizontal gap = 2
Step 3: Compute vertical gaps
| Previous Boundary | Current Boundary | Gap |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 4 | 3 |
Maximum vertical gap = 3
Step 4: Compute area
2 * 3 = 6
Final answer:
6
Example 3
h = 5
w = 4
horizontalCuts = [3]
verticalCuts = [3]
Step 1: Horizontal gaps
| Previous Boundary | Current Boundary | Gap |
|---|---|---|
| 0 | 3 | 3 |
| 3 | 5 | 2 |
Maximum horizontal gap = 3
Step 2: Vertical gaps
| Previous Boundary | Current Boundary | Gap |
|---|---|---|
| 0 | 3 | 3 |
| 3 | 4 | 1 |
Maximum vertical gap = 3
Step 3: Compute area
3 * 3 = 9
Final answer:
9
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(m log m + n log n) | Sorting dominates the runtime |
| Space | O(1) or O(log n) | Depends on the sorting implementation |
The dominant cost comes from sorting the cut arrays. After sorting, we only perform linear scans to compute the maximum gaps.
The algorithm does not construct all cake pieces, which is what makes it efficient enough for the problem constraints.
Test Cases
from typing import List
class Solution:
def maxArea(self, h: int, w: int, horizontalCuts: List[int], verticalCuts: List[int]) -> int:
MOD = 10**9 + 7
horizontalCuts.sort()
verticalCuts.sort()
max_horizontal_gap = horizontalCuts[0]
for i in range(1, len(horizontalCuts)):
max_horizontal_gap = max(
max_horizontal_gap,
horizontalCuts[i] - horizontalCuts[i - 1]
)
max_horizontal_gap = max(
max_horizontal_gap,
h - horizontalCuts[-1]
)
max_vertical_gap = verticalCuts[0]
for i in range(1, len(verticalCuts)):
max_vertical_gap = max(
max_vertical_gap,
verticalCuts[i] - verticalCuts[i - 1]
)
max_vertical_gap = max(
max_vertical_gap,
w - verticalCuts[-1]
)
return (max_horizontal_gap * max_vertical_gap) % MOD
sol = Solution()
assert sol.maxArea(5, 4, [1, 2, 4], [1, 3]) == 4
# Basic example from problem statement
assert sol.maxArea(5, 4, [3, 1], [1]) == 6
# Unsorted cuts
assert sol.maxArea(5, 4, [3], [3]) == 9
# Single cut in each direction
assert sol.maxArea(1000000000, 1000000000, [2], [2]) == 81
# Large dimensions with modulo handling
assert sol.maxArea(8, 10, [1, 7], [2, 9]) == 42
# Largest gaps occur near boundaries
assert sol.maxArea(6, 6, [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]) == 1
# Every piece has area 1
assert sol.maxArea(9, 8, [5], [3]) == 20
# Large center piece
assert sol.maxArea(7, 7, [1, 6], [1, 6]) == 25
# Largest piece in the middle
Test Case Summary
| Test | Why |
|---|---|
(5,4,[1,2,4],[1,3]) |
Basic example |
(5,4,[3,1],[1]) |
Ensures sorting is handled |
(5,4,[3],[3]) |
Minimal number of cuts |
| Large dimensions | Verifies modulo and overflow safety |
| Boundary-heavy cuts | Ensures edge gaps are considered |
| Dense cuts | Tests smallest possible segments |
| Single central cuts | Verifies interior maximum piece |
| Symmetric cuts | Tests middle-region maximum |
Edge Cases
One important edge case occurs when the largest segment lies against the boundary of the cake rather than between two cuts. For example, if the first horizontal cut is very far from the top edge, the maximum gap may be horizontalCuts[0]. A buggy implementation that only checks consecutive cuts would miss this. The solution explicitly checks both outer boundaries.
Another important case is unsorted input. The problem does not guarantee that cuts are provided in sorted order. If we compute gaps without sorting first, we may get negative distances or incorrect maximums. The implementation sorts both arrays before any calculations.
A third important edge case involves integer overflow. The cake dimensions can reach 10^9, so the area may approach 10^18. This exceeds 32-bit integer limits. The Go solution uses int64 during multiplication, and the Python solution naturally handles large integers safely.
A final subtle edge case occurs when there is only one cut in a direction. In that scenario, there are only two segments, one on each side of the cut. The implementation correctly handles this because it separately checks the distance to both boundaries.