Facebook Pixel

2975. Maximum Square Area by Removing Fences From a Field

MediumArrayHash TableEnumeration
Leetcode Link

Problem Description

You have a rectangular field with corners at coordinates (1, 1) and (m, n). The field contains some internal fences:

  • Horizontal fences run from (hFences[i], 1) to (hFences[i], n)
  • Vertical fences run from (1, vFences[i]) to (m, vFences[i])

The field is also surrounded by boundary fences that cannot be removed:

  • Two horizontal boundaries: from (1, 1) to (1, n) and from (m, 1) to (m, n)
  • Two vertical boundaries: from (1, 1) to (m, 1) and from (1, n) to (m, n)

Your task is to find the maximum area of a square field that can be created by removing some (or none) of the internal fences. The square must be formed by selecting two horizontal lines (either boundaries or fences) and two vertical lines (either boundaries or fences) such that the distance between the horizontal lines equals the distance between the vertical lines.

Return the maximum square area modulo 10^9 + 7. If no square field can be formed, return -1.

For example, if you can create a square with side length d, the area would be d^2. You need to find the largest possible d where:

  • The distance d exists between some pair of horizontal lines (considering both boundaries and fences)
  • The same distance d exists between some pair of vertical lines (considering both boundaries and fences)
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

To form a square field, we need to find two horizontal lines that are distance d apart and two vertical lines that are also distance d apart. The key insight is that we don't need to track which specific fences we remove - we only care about what distances are achievable.

Think of it this way: if we have horizontal fences at positions [2, 5, 7] plus boundaries at 1 and m, we can create various distances by choosing any two of these positions. For instance, choosing positions 2 and 7 gives us a distance of 5. Similarly for vertical fences.

The crucial observation is that a square with side length d can be formed if and only if:

  1. Distance d can be achieved between some pair of horizontal lines (including boundaries)
  2. The same distance d can be achieved between some pair of vertical lines (including boundaries)

This naturally leads to a set intersection approach:

  • Calculate all possible distances between pairs of horizontal lines (including boundaries at 1 and m)
  • Calculate all possible distances between pairs of vertical lines (including boundaries at 1 and n)
  • Find the common distances that appear in both sets
  • The largest common distance gives us the maximum square side length

Why does this work? Because if distance d appears in both sets, it means we can select two horizontal lines d units apart AND two vertical lines d units apart, forming a square of side length d. The area would then be d^2.

The beauty of this approach is that it reduces a potentially complex geometric problem to a simple set operation - finding the intersection of two sets of distances and taking the maximum value.

Solution Approach

The solution implements the intuition using a helper function and set operations:

Step 1: Generate All Possible Distances

The helper function f(nums: List[int], k: int) takes a list of fence positions and a boundary value k:

  • First, it extends the list with boundary positions [1, k] to include the field boundaries
  • Sorts the combined list to have positions in order
  • Uses combinations(nums, 2) to generate all pairs of positions
  • Calculates the distance b - a for each pair (a, b) where a < b (guaranteed by combinations on sorted list)
  • Returns a set containing all unique distances

Step 2: Calculate Horizontal and Vertical Distances

  • Call f(hFences, m) to get all possible horizontal distances hs
    • This includes distances between any two horizontal lines (fences + boundaries at positions 1 and m)
  • Call f(vFences, n) to get all possible vertical distances vs
    • This includes distances between any two vertical lines (fences + boundaries at positions 1 and n)

Step 3: Find Common Distances

  • Use set intersection hs & vs to find distances that appear in both sets
  • These common distances represent possible square side lengths
  • Use max(hs & vs, default=0) to find the largest common distance
    • The default=0 handles the case when there's no intersection (no square possible)

Step 4: Calculate the Result

  • If ans (maximum common distance) is non-zero:
    • Calculate the square area as ans**2
    • Return the result modulo 10**9 + 7
  • If ans is 0 (no common distances found):
    • Return -1 to indicate no square field is possible

The time complexity is O(p^2 + q^2) where p and q are the total number of horizontal and vertical lines respectively (including boundaries). The space complexity is O(p^2 + q^2) for storing all possible distances in the sets.

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's walk through a small example where m = 6, n = 7, hFences = [3], and vFences = [4].

Step 1: Identify all horizontal lines

  • Boundary lines at positions: 1 and 6
  • Fence lines at position: 3
  • All horizontal lines: [1, 3, 6]

Step 2: Calculate all possible horizontal distances

  • Distance between positions 1 and 3: 3 - 1 = 2
  • Distance between positions 1 and 6: 6 - 1 = 5
  • Distance between positions 3 and 6: 6 - 3 = 3
  • Set of horizontal distances: {2, 3, 5}

Step 3: Identify all vertical lines

  • Boundary lines at positions: 1 and 7
  • Fence lines at position: 4
  • All vertical lines: [1, 4, 7]

Step 4: Calculate all possible vertical distances

  • Distance between positions 1 and 4: 4 - 1 = 3
  • Distance between positions 1 and 7: 7 - 1 = 6
  • Distance between positions 4 and 7: 7 - 4 = 3
  • Set of vertical distances: {3, 6}

Step 5: Find common distances

  • Horizontal distances: {2, 3, 5}
  • Vertical distances: {3, 6}
  • Intersection: {2, 3, 5} ∩ {3, 6} = {3}
  • Maximum common distance: 3

Step 6: Calculate the result

  • Maximum square side length: 3
  • Maximum square area: 3² = 9
  • Return: 9 % (10⁹ + 7) = 9

This means we can form a square field with side length 3. For instance:

  • Using horizontal lines at positions 3 and 6 (distance = 3)
  • Using vertical lines at positions 1 and 4 (distance = 3)
  • Or using vertical lines at positions 4 and 7 (distance = 3)

The key insight is that we don't need to track which specific fences to remove - we only need to find matching distances in both horizontal and vertical directions to form a square.

Solution Implementation

1class Solution:
2    def maximizeSquareArea(
3        self, m: int, n: int, hFences: List[int], vFences: List[int]
4    ) -> int:
5        """
6        Find the maximum square area that can be formed in a field with fences.
7      
8        Args:
9            m: Width of the field
10            n: Height of the field
11            hFences: List of horizontal fence positions
12            vFences: List of vertical fence positions
13          
14        Returns:
15            Maximum square area modulo 10^9 + 7, or -1 if no square can be formed
16        """
17      
18        def get_all_distances(fence_positions: List[int], field_size: int) -> Set[int]:
19            """
20            Calculate all possible distances between any two fence positions,
21            including the field boundaries.
22          
23            Args:
24                fence_positions: List of fence positions
25                field_size: Size of the field dimension (width or height)
26              
27            Returns:
28                Set of all possible distances between fence pairs
29            """
30            # Add field boundaries (1 and field_size) to fence positions
31            all_positions = fence_positions + [1, field_size]
32            # Sort positions for consistent processing
33            all_positions.sort()
34          
35            # Calculate all possible distances between any two positions
36            distances = set()
37            for i in range(len(all_positions)):
38                for j in range(i + 1, len(all_positions)):
39                    distance = all_positions[j] - all_positions[i]
40                    distances.add(distance)
41          
42            return distances
43      
44        # Modulo value for the result
45        MOD = 10**9 + 7
46      
47        # Get all possible horizontal distances
48        horizontal_distances = get_all_distances(hFences, m)
49      
50        # Get all possible vertical distances
51        vertical_distances = get_all_distances(vFences, n)
52      
53        # Find common distances (these can form squares)
54        common_distances = horizontal_distances & vertical_distances
55      
56        # Get the maximum common distance (largest square side length)
57        max_side_length = max(common_distances, default=0)
58      
59        # Calculate and return the area
60        if max_side_length > 0:
61            area = (max_side_length ** 2) % MOD
62            return area
63        else:
64            # No square can be formed
65            return -1
66
1class Solution {
2    public int maximizeSquareArea(int m, int n, int[] hFences, int[] vFences) {
3        // Get all possible horizontal distances between fences (including boundaries)
4        Set<Integer> horizontalDistances = calculateAllDistances(hFences, m);
5      
6        // Get all possible vertical distances between fences (including boundaries)
7        Set<Integer> verticalDistances = calculateAllDistances(vFences, n);
8      
9        // Find common distances that can form squares (equal horizontal and vertical sides)
10        horizontalDistances.retainAll(verticalDistances);
11      
12        // Find the maximum square side length
13        int maxSideLength = -1;
14        final int MOD = (int) 1e9 + 7;
15      
16        for (int sideLength : horizontalDistances) {
17            maxSideLength = Math.max(maxSideLength, sideLength);
18        }
19      
20        // Calculate and return the area of the maximum square, or -1 if no square is possible
21        return maxSideLength > 0 ? (int) (1L * maxSideLength * maxSideLength % MOD) : -1;
22    }
23
24    /**
25     * Calculate all possible distances between fence positions including boundaries
26     * @param fences Array of fence positions
27     * @param boundaryPosition The boundary position (m for horizontal, n for vertical)
28     * @return Set of all possible distances between any two positions
29     */
30    private Set<Integer> calculateAllDistances(int[] fences, int boundaryPosition) {
31        int fenceCount = fences.length;
32      
33        // Create a new array including the original fences and two boundaries (1 and boundaryPosition)
34        int[] allPositions = Arrays.copyOf(fences, fenceCount + 2);
35        allPositions[fenceCount] = 1;                    // Starting boundary
36        allPositions[fenceCount + 1] = boundaryPosition; // Ending boundary
37      
38        // Sort positions to calculate distances efficiently
39        Arrays.sort(allPositions);
40      
41        // Store all possible distances between any two positions
42        Set<Integer> distances = new HashSet<>();
43      
44        // Calculate distance between every pair of positions
45        for (int i = 0; i < allPositions.length; ++i) {
46            for (int j = 0; j < i; ++j) {
47                distances.add(allPositions[i] - allPositions[j]);
48            }
49        }
50      
51        return distances;
52    }
53}
54
1class Solution {
2public:
3    int maximizeSquareArea(int m, int n, vector<int>& hFences, vector<int>& vFences) {
4        // Lambda function to calculate all possible distances between fence positions
5        auto calculateDistances = [](vector<int>& fences, int boundary) -> unordered_set<int> {
6            // Add the boundary positions (1 and boundary) to the fence list
7            fences.push_back(boundary);
8            fences.push_back(1);
9          
10            // Sort all fence positions for systematic distance calculation
11            sort(fences.begin(), fences.end());
12          
13            // Store all possible distances in a set
14            unordered_set<int> distances;
15          
16            // Calculate distance between every pair of fence positions
17            for (int i = 0; i < fences.size(); ++i) {
18                for (int j = 0; j < i; ++j) {
19                    distances.insert(fences[i] - fences[j]);
20                }
21            }
22          
23            return distances;
24        };
25      
26        // Calculate all possible horizontal distances
27        unordered_set<int> horizontalDistances = calculateDistances(hFences, m);
28      
29        // Calculate all possible vertical distances
30        unordered_set<int> verticalDistances = calculateDistances(vFences, n);
31      
32        // Find the maximum distance that exists in both horizontal and vertical sets
33        int maxSideLength = 0;
34        for (int distance : horizontalDistances) {
35            // Check if this distance can form a square (exists in both dimensions)
36            if (verticalDistances.count(distance)) {
37                maxSideLength = max(maxSideLength, distance);
38            }
39        }
40      
41        // Define modulo for the result
42        const int MOD = 1e9 + 7;
43      
44        // Return the area of the largest square, or -1 if no square is possible
45        return maxSideLength > 0 ? (1LL * maxSideLength * maxSideLength) % MOD : -1;
46    }
47};
48
1/**
2 * Calculates the maximum square area that can be formed using the given fences
3 * @param m - The maximum horizontal boundary
4 * @param n - The maximum vertical boundary
5 * @param hFences - Array of horizontal fence positions
6 * @param vFences - Array of vertical fence positions
7 * @returns The area of the largest square modulo 1000000007, or -1 if no square can be formed
8 */
9function maximizeSquareArea(m: number, n: number, hFences: number[], vFences: number[]): number {
10    /**
11     * Helper function to calculate all possible distances between fence positions
12     * @param fencePositions - Array of fence positions
13     * @param boundary - The maximum boundary value
14     * @returns Set of all possible distances between any two positions
15     */
16    const calculateDistances = (fencePositions: number[], boundary: number): Set<number> => {
17        // Add the start (1) and end (boundary) positions to the fence array
18        fencePositions.push(1, boundary);
19      
20        // Sort positions in ascending order
21        fencePositions.sort((a, b) => a - b);
22      
23        // Store all possible distances
24        const distances: Set<number> = new Set();
25      
26        // Calculate distance between every pair of positions
27        for (let i = 0; i < fencePositions.length; ++i) {
28            for (let j = 0; j < i; ++j) {
29                distances.add(fencePositions[i] - fencePositions[j]);
30            }
31        }
32      
33        return distances;
34    };
35  
36    // Calculate all possible horizontal distances
37    const horizontalDistances = calculateDistances(hFences, m);
38  
39    // Calculate all possible vertical distances
40    const verticalDistances = calculateDistances(vFences, n);
41  
42    // Find the maximum side length that exists in both horizontal and vertical distances
43    let maxSideLength = 0;
44    for (const horizontalDistance of horizontalDistances) {
45        // Check if this distance can form a square (exists in both dimensions)
46        if (verticalDistances.has(horizontalDistance)) {
47            maxSideLength = Math.max(maxSideLength, horizontalDistance);
48        }
49    }
50  
51    // Calculate the area and return with modulo, or -1 if no square found
52    const MOD = 1000000007n;
53    return maxSideLength ? Number(BigInt(maxSideLength) ** 2n % MOD) : -1;
54}
55

Time and Space Complexity

The time complexity is O(h^2 + v^2), where h is the length of hFences and v is the length of vFences.

Breaking down the analysis:

  • The function f is called twice - once for horizontal fences and once for vertical fences
  • Inside function f, after extending the list with 2 elements (boundaries), we have h+2 horizontal positions and v+2 vertical positions
  • Sorting takes O((h+2)log(h+2)) for horizontal and O((v+2)log(v+2)) for vertical
  • The combinations operation generates all pairs from the sorted list, which creates C(h+2, 2) = (h+2)(h+1)/2 pairs for horizontal and C(v+2, 2) = (v+2)(v+1)/2 pairs for vertical
  • Computing differences for all pairs takes O(h^2) for horizontal and O(v^2) for vertical
  • The set intersection operation hs & vs takes O(min(|hs|, |vs|)) which is bounded by O(h^2 + v^2)
  • Finding the maximum takes linear time in the size of the intersection

Since O(h^2) and O(v^2) dominate the sorting operations, the overall time complexity is O(h^2 + v^2).

The space complexity is O(h^2 + v^2):

  • The set hs stores up to (h+2)(h+1)/2 differences, which is O(h^2)
  • The set vs stores up to (v+2)(v+1)/2 differences, which is O(v^2)
  • The intersection creates a new set with size at most min(|hs|, |vs|)
  • Other variables use constant space

Therefore, the total space complexity is O(h^2 + v^2).

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

Common Pitfalls

1. Integer Overflow When Calculating Square Area

The most critical pitfall in this problem is calculating max_side_length ** 2 without considering integer overflow. Since the field dimensions can be as large as 10^9, the maximum possible side length is also up to 10^9. When squaring this value, we get 10^18, which exceeds the typical 32-bit integer limit and can cause overflow issues in some programming languages.

Incorrect approach:

# This might cause issues in languages with fixed integer sizes
area = max_side_length ** 2
return area % MOD

Correct approach:

# Apply modulo during calculation to prevent overflow
area = pow(max_side_length, 2, MOD)  # Built-in modular exponentiation
# Or explicitly handle large numbers
area = (max_side_length * max_side_length) % MOD

2. Forgetting to Include Boundary Fences

A common mistake is only considering the internal fences and forgetting that the field boundaries at positions 1 and m (for horizontal) and 1 and n (for vertical) are also valid lines for forming squares.

Incorrect approach:

# Only using internal fences
distances = set()
for i in range(len(hFences)):
    for j in range(i + 1, len(hFences)):
        distances.add(hFences[j] - hFences[i])

Correct approach:

# Include boundaries with internal fences
all_positions = hFences + [1, m]  # Add boundaries
all_positions.sort()
# Then calculate distances from all positions

3. Not Handling Empty Intersection Properly

When there are no common distances between horizontal and vertical possibilities, the intersection will be empty. Using max() on an empty set will raise a ValueError.

Incorrect approach:

max_side_length = max(horizontal_distances & vertical_distances)  # Raises error if empty

Correct approach:

max_side_length = max(horizontal_distances & vertical_distances, default=0)
# Or check explicitly:
common_distances = horizontal_distances & vertical_distances
if not common_distances:
    return -1
max_side_length = max(common_distances)

4. Inefficient Distance Calculation

Using nested loops without optimization or using combinations incorrectly can lead to inefficiency or errors.

Less efficient approach:

# Creating unnecessary intermediate lists
from itertools import combinations
all_pairs = list(combinations(all_positions, 2))
distances = set([b - a for a, b in all_pairs])

More efficient approach:

# Direct set construction without intermediate list
distances = {b - a for a, b in combinations(sorted(all_positions), 2)}

5. Not Sorting Positions Before Distance Calculation

If positions aren't sorted, you might calculate negative distances or need additional checks.

Incorrect approach:

# Without sorting, might get negative distances
for a, b in combinations(all_positions, 2):
    distances.add(abs(b - a))  # Need abs() to handle order

Correct approach:

all_positions.sort()  # Sort first
for a, b in combinations(all_positions, 2):
    distances.add(b - a)  # No need for abs() since b > a is guaranteed
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which of the following shows the order of node visit in a Breadth-first Search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More