2975. Maximum Square Area by Removing Fences From a Field
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
dexists between some pair of horizontal lines (considering both boundaries and fences) - The same distance
dexists between some pair of vertical lines (considering both boundaries and fences)
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:
- Distance
dcan be achieved between some pair of horizontal lines (including boundaries) - The same distance
dcan 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
1andm) - Calculate all possible distances between pairs of vertical lines (including boundaries at
1andn) - 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 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 661class 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} 541class 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}; 481/** 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} 55Solution 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 - afor each pair(a, b)wherea < 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 distanceshs- This includes distances between any two horizontal lines (fences + boundaries at positions
1andm)
- This includes distances between any two horizontal lines (fences + boundaries at positions
- Call
f(vFences, n)to get all possible vertical distancesvs- This includes distances between any two vertical lines (fences + boundaries at positions
1andn)
- This includes distances between any two vertical lines (fences + boundaries at positions
Step 3: Find Common Distances
- Use set intersection
hs & vsto 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=0handles the case when there's no intersection (no square possible)
- The
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
- Calculate the square area as
- If
ansis0(no common distances found):- Return
-1to indicate no square field is possible
- Return
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 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample 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.
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
fis called twice - once for horizontal fences and once for vertical fences - Inside function
f, after extending the list with 2 elements (boundaries), we haveh+2horizontal positions andv+2vertical positions - Sorting takes
O((h+2)log(h+2))for horizontal andO((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)/2pairs for horizontal andC(v+2, 2) = (v+2)(v+1)/2pairs for vertical - Computing differences for all pairs takes
O(h^2)for horizontal andO(v^2)for vertical - The set intersection operation
hs & vstakesO(min(|hs|, |vs|))which is bounded byO(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
hsstores up to(h+2)(h+1)/2differences, which isO(h^2) - The set
vsstores up to(v+2)(v+1)/2differences, which isO(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
A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".
What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!