Facebook Pixel

1465. Maximum Area of a Piece of Cake After Horizontal and Vertical Cuts

Problem Description

You have a rectangular cake with dimensions h (height) ร— w (width). You need to make cuts on this cake using two sets of cutting positions:

  • horizontalCuts[i] represents the distance from the top edge where you make the i-th horizontal cut
  • verticalCuts[j] represents the distance from the left edge where you make the j-th vertical cut

After making all the cuts specified in both arrays, the cake will be divided into multiple rectangular pieces. Your task is to find the maximum area among all these pieces.

For example, if you have a cake of size 5ร—4 and make horizontal cuts at distances 1 and 3 from the top, and vertical cuts at distances 1 and 3 from the left, you'll create several rectangular pieces. The pieces will have various sizes based on the distances between consecutive cuts (including the edges of the original cake).

The key insight is that the area of any piece is determined by the product of:

  • The distance between two consecutive horizontal cuts (or between a cut and an edge)
  • The distance between two consecutive vertical cuts (or between a cut and an edge)

To find the maximum area, you need to find the maximum gap between consecutive horizontal positions and the maximum gap between consecutive vertical positions, then multiply these two values.

Since the result can be very large, return the answer modulo 10^9 + 7.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When we make cuts on the cake, we're essentially creating grid lines. Each piece of cake is bounded by two consecutive horizontal lines and two consecutive vertical lines. The area of each piece equals the height difference between its horizontal boundaries multiplied by the width difference between its vertical boundaries.

The key observation is that we can think about this problem independently in two dimensions. For the horizontal dimension, we need to find all the gaps between consecutive cuts (including the edges at 0 and h). Similarly for the vertical dimension with gaps between cuts (including edges at 0 and w).

Since any piece is formed by choosing one horizontal gap and one vertical gap, and we want the maximum area, we should choose the largest horizontal gap and multiply it by the largest vertical gap. This works because:

  • Every piece must use exactly one horizontal gap and one vertical gap
  • The gaps are independent of each other
  • To maximize the product of two positive numbers, we should choose the largest available values

For example, if the maximum horizontal gap is 3 units and the maximum vertical gap is 4 units, then the largest possible piece will have area 3 ร— 4 = 12.

To find these maximum gaps efficiently, we sort both arrays of cuts, add the boundary positions (0 and h for horizontal, 0 and w for vertical), and then iterate through consecutive pairs to find the maximum difference. The sorting ensures that we can easily find the distance between consecutive cuts by simple subtraction.

The modulo operation 10^9 + 7 is applied at the end to handle potential overflow issues with large numbers.

Learn more about Greedy and Sorting patterns.

Solution Approach

The implementation follows these steps:

  1. Add boundary positions: First, we extend both horizontalCuts and verticalCuts arrays by adding the boundary positions. For horizontal cuts, we add 0 (top edge) and h (bottom edge). For vertical cuts, we add 0 (left edge) and w (right edge). This ensures we consider the gaps between cuts and the cake edges.

  2. Sort the arrays: We sort both horizontalCuts and verticalCuts in ascending order. After sorting, consecutive elements in the array represent adjacent cutting positions or edges.

  3. Find maximum gaps:

    • For horizontal cuts, we iterate through consecutive pairs using pairwise(horizontalCuts) and calculate the difference b - a for each pair (a, b). We keep track of the maximum difference as x.
    • Similarly for vertical cuts, we find the maximum difference between consecutive positions and store it as y.
  4. Calculate the result: The maximum area is simply the product of the maximum horizontal gap x and the maximum vertical gap y. We apply modulo 10^9 + 7 to the final result to prevent overflow.

The pairwise function is a Python utility that creates pairs of consecutive elements from an iterable. For example, pairwise([1, 3, 5, 8]) yields (1, 3), (3, 5), (5, 8).

Time Complexity: O(n log n + m log m) where n is the length of horizontalCuts and m is the length of verticalCuts, due to the sorting operations.

Space Complexity: O(1) if we don't count the space used for sorting, or O(n + m) if we do.

The beauty of this solution is its simplicity - by recognizing that horizontal and vertical dimensions are independent, we can solve each dimension separately and combine the results with a simple multiplication.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to illustrate the solution approach.

Example: We have a cake with height h = 5 and width w = 4. We make:

  • Horizontal cuts at positions [1, 2, 4] (distances from top)
  • Vertical cuts at position [3] (distance from left)

Step 1: Add boundary positions

  • Horizontal positions become: [0, 1, 2, 4, 5] (added 0 for top edge and 5 for bottom edge)
  • Vertical positions become: [0, 3, 4] (added 0 for left edge and 4 for right edge)

Step 2: Sort the arrays In this case, after adding boundaries:

  • Horizontal: [0, 1, 2, 4, 5] (already sorted)
  • Vertical: [0, 3, 4] (already sorted)

Step 3: Find maximum gaps

For horizontal gaps (between consecutive positions):

  • Gap between 0 and 1: 1 - 0 = 1
  • Gap between 1 and 2: 2 - 1 = 1
  • Gap between 2 and 4: 4 - 2 = 2
  • Gap between 4 and 5: 5 - 4 = 1
  • Maximum horizontal gap x = 2

For vertical gaps:

  • Gap between 0 and 3: 3 - 0 = 3
  • Gap between 3 and 4: 4 - 3 = 1
  • Maximum vertical gap y = 3

Step 4: Calculate the result Maximum area = x ร— y = 2 ร— 3 = 6

This represents a piece that spans 2 units vertically (from position 2 to position 4) and 3 units horizontally (from position 0 to position 3). The final answer would be 6 % (10^9 + 7) = 6.

The cake is divided into 8 pieces total, with areas: 3, 1, 3, 1, 6, 2, 3, 1. The maximum among these is indeed 6.

Solution Implementation

1class Solution:
2    def maxArea(
3        self, h: int, w: int, horizontalCuts: List[int], verticalCuts: List[int]
4    ) -> int:
5        # Add boundaries (0 and max values) to both cut lists
6        horizontalCuts.extend([0, h])
7        verticalCuts.extend([0, w])
8      
9        # Sort both lists to process consecutive cuts
10        horizontalCuts.sort()
11        verticalCuts.sort()
12      
13        # Find maximum gap between consecutive horizontal cuts
14        max_height = 0
15        for i in range(1, len(horizontalCuts)):
16            max_height = max(max_height, horizontalCuts[i] - horizontalCuts[i - 1])
17      
18        # Find maximum gap between consecutive vertical cuts
19        max_width = 0
20        for i in range(1, len(verticalCuts)):
21            max_width = max(max_width, verticalCuts[i] - verticalCuts[i - 1])
22      
23        # Return the area of the largest piece modulo 10^9 + 7
24        MOD = 10**9 + 7
25        return (max_height * max_width) % MOD
26
1class Solution {
2    public int maxArea(int h, int w, int[] horizontalCuts, int[] verticalCuts) {
3        // Define modulo constant for result overflow prevention
4        final int MOD = (int) 1e9 + 7;
5      
6        // Sort both cut arrays to process consecutive cuts
7        Arrays.sort(horizontalCuts);
8        Arrays.sort(verticalCuts);
9      
10        // Get the lengths of both cut arrays
11        int horizontalCutsCount = horizontalCuts.length;
12        int verticalCutsCount = verticalCuts.length;
13      
14        // Initialize max horizontal distance considering edges
15        // Check distance from top edge to first cut and from last cut to bottom edge
16        long maxHorizontalDistance = Math.max(
17            horizontalCuts[0],                                    // Distance from top edge (0) to first cut
18            h - horizontalCuts[horizontalCutsCount - 1]          // Distance from last cut to bottom edge
19        );
20      
21        // Initialize max vertical distance considering edges
22        // Check distance from left edge to first cut and from last cut to right edge
23        long maxVerticalDistance = Math.max(
24            verticalCuts[0],                                      // Distance from left edge (0) to first cut
25            w - verticalCuts[verticalCutsCount - 1]              // Distance from last cut to right edge
26        );
27      
28        // Find maximum horizontal distance between consecutive cuts
29        for (int i = 1; i < horizontalCutsCount; i++) {
30            long currentDistance = horizontalCuts[i] - horizontalCuts[i - 1];
31            maxHorizontalDistance = Math.max(maxHorizontalDistance, currentDistance);
32        }
33      
34        // Find maximum vertical distance between consecutive cuts
35        for (int i = 1; i < verticalCutsCount; i++) {
36            long currentDistance = verticalCuts[i] - verticalCuts[i - 1];
37            maxVerticalDistance = Math.max(maxVerticalDistance, currentDistance);
38        }
39      
40        // Calculate the maximum area and apply modulo
41        // Maximum area = maximum horizontal distance ร— maximum vertical distance
42        return (int) ((maxHorizontalDistance * maxVerticalDistance) % MOD);
43    }
44}
45
1class Solution {
2public:
3    int maxArea(int h, int w, vector<int>& horizontalCuts, vector<int>& verticalCuts) {
4        // Add boundaries (top/bottom for horizontal, left/right for vertical)
5        horizontalCuts.push_back(0);
6        horizontalCuts.push_back(h);
7        verticalCuts.push_back(0);
8        verticalCuts.push_back(w);
9      
10        // Sort both arrays to process cuts in order
11        sort(horizontalCuts.begin(), horizontalCuts.end());
12        sort(verticalCuts.begin(), verticalCuts.end());
13      
14        // Find maximum gap between consecutive horizontal cuts
15        int maxHorizontalGap = 0;
16        for (int i = 1; i < horizontalCuts.size(); ++i) {
17            maxHorizontalGap = max(maxHorizontalGap, horizontalCuts[i] - horizontalCuts[i - 1]);
18        }
19      
20        // Find maximum gap between consecutive vertical cuts
21        int maxVerticalGap = 0;
22        for (int i = 1; i < verticalCuts.size(); ++i) {
23            maxVerticalGap = max(maxVerticalGap, verticalCuts[i] - verticalCuts[i - 1]);
24        }
25      
26        // Calculate the area of the largest piece (max horizontal gap * max vertical gap)
27        // Use 1LL to ensure 64-bit multiplication before taking modulo
28        const int MOD = 1e9 + 7;
29        return (1LL * maxHorizontalGap * maxVerticalGap) % MOD;
30    }
31};
32
1/**
2 * Finds the maximum area of a rectangle piece after cutting a rectangular cake
3 * @param h - Height of the rectangular cake
4 * @param w - Width of the rectangular cake
5 * @param horizontalCuts - Array of positions where horizontal cuts are made
6 * @param verticalCuts - Array of positions where vertical cuts are made
7 * @returns Maximum area of a rectangle piece modulo 10^9 + 7
8 */
9function maxArea(h: number, w: number, horizontalCuts: number[], verticalCuts: number[]): number {
10    // Define modulo constant for large number handling
11    const MODULO: number = 1e9 + 7;
12  
13    // Add boundaries (0 and max values) to both cut arrays
14    horizontalCuts.push(0, h);
15    verticalCuts.push(0, w);
16  
17    // Sort both arrays in ascending order to calculate consecutive differences
18    horizontalCuts.sort((a: number, b: number) => a - b);
19    verticalCuts.sort((a: number, b: number) => a - b);
20  
21    // Initialize variables to track maximum distances
22    let maxHorizontalGap: number = 0;
23    let maxVerticalGap: number = 0;
24  
25    // Find the maximum gap between consecutive horizontal cuts
26    for (let i: number = 1; i < horizontalCuts.length; i++) {
27        const currentGap: number = horizontalCuts[i] - horizontalCuts[i - 1];
28        maxHorizontalGap = Math.max(maxHorizontalGap, currentGap);
29    }
30  
31    // Find the maximum gap between consecutive vertical cuts
32    for (let i: number = 1; i < verticalCuts.length; i++) {
33        const currentGap: number = verticalCuts[i] - verticalCuts[i - 1];
34        maxVerticalGap = Math.max(maxVerticalGap, currentGap);
35    }
36  
37    // Calculate the maximum area using BigInt to handle potential overflow
38    // Then apply modulo operation and convert back to number
39    const maxArea: bigint = (BigInt(maxHorizontalGap) * BigInt(maxVerticalGap)) % BigInt(MODULO);
40    return Number(maxArea);
41}
42

Time and Space Complexity

The time complexity is O(m log m + n log n), where m and n are the lengths of horizontalCuts and verticalCuts, respectively. This is because:

  • The extend() operations add constant elements to each list in O(1) time
  • The sort() operation on horizontalCuts (now with m+2 elements) takes O((m+2) log(m+2)) = O(m log m) time
  • The sort() operation on verticalCuts (now with n+2 elements) takes O((n+2) log(n+2)) = O(n log n) time
  • The pairwise() iterations and max operations take O(m) and O(n) time respectively, which are dominated by the sorting operations

The space complexity is O(log m + log n). This comes from:

  • The sorting algorithms (typically Timsort in Python) use O(log m) and O(log n) space for the recursion stack
  • The pairwise() function creates an iterator that uses O(1) additional space
  • The extend() operations modify the lists in-place, though they do increase the list sizes by constant amounts

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Modifying Input Arrays In-Place

The code uses extend() to add boundaries to the input arrays, which modifies them directly. This can cause issues if the same arrays are used elsewhere or if the function is called multiple times with the same inputs.

Problem Example:

h_cuts = [1, 3]
v_cuts = [1, 3]
solution = Solution()
result1 = solution.maxArea(5, 4, h_cuts, v_cuts)
# h_cuts is now [1, 3, 0, 5] - modified!
result2 = solution.maxArea(5, 4, h_cuts, v_cuts)  
# Wrong result because h_cuts already contains boundaries

Solution: Create copies of the arrays or use list concatenation:

horizontalCuts = sorted(horizontalCuts + [0, h])
verticalCuts = sorted(verticalCuts + [0, w])

2. Integer Overflow in Other Languages

While Python handles large integers automatically, in languages like Java or C++, computing max_height * max_width directly might cause integer overflow before applying modulo.

Solution for other languages: Apply modulo during multiplication or use long/64-bit integers:

# For languages with overflow concerns:
return ((max_height % MOD) * (max_width % MOD)) % MOD

3. Forgetting Edge Cases

Not handling empty cut arrays properly. While the problem likely guarantees non-empty arrays, defensive programming suggests checking.

Solution:

if not horizontalCuts:
    horizontalCuts = []
if not verticalCuts:
    verticalCuts = []

4. Using pairwise() Incorrectly

The explanation mentions pairwise() but the actual code uses manual indexing. If using pairwise() (Python 3.10+), ensure proper import:

from itertools import pairwise

# Then use:
max_height = max(b - a for a, b in pairwise(horizontalCuts))
max_width = max(b - a for a, b in pairwise(verticalCuts))

Corrected Complete Solution:

class Solution:
    def maxArea(self, h: int, w: int, horizontalCuts: List[int], verticalCuts: List[int]) -> int:
        # Create new sorted lists with boundaries
        horizontalCuts = sorted(horizontalCuts + [0, h])
        verticalCuts = sorted(verticalCuts + [0, w])
      
        # Find maximum gaps
        max_height = max(horizontalCuts[i] - horizontalCuts[i-1] 
                        for i in range(1, len(horizontalCuts)))
        max_width = max(verticalCuts[i] - verticalCuts[i-1] 
                       for i in range(1, len(verticalCuts)))
      
        # Return result with modulo
        return (max_height * max_width) % (10**9 + 7)
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Given a sorted array of integers and an integer called target, find the element that equals to the target and return its index. Select the correct code that fills the ___ in the given code snippet.

1def binary_search(arr, target):
2    left, right = 0, len(arr) - 1
3    while left ___ right:
4        mid = (left + right) // 2
5        if arr[mid] == target:
6            return mid
7        if arr[mid] < target:
8            ___ = mid + 1
9        else:
10            ___ = mid - 1
11    return -1
12
1public static int binarySearch(int[] arr, int target) {
2    int left = 0;
3    int right = arr.length - 1;
4
5    while (left ___ right) {
6        int mid = left + (right - left) / 2;
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16
1function binarySearch(arr, target) {
2    let left = 0;
3    let right = arr.length - 1;
4
5    while (left ___ right) {
6        let mid = left + Math.trunc((right - left) / 2);
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16

Recommended Readings

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!

Load More