Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given an integer n representing the dimensions of an n x n grid, with the origin at the bottom-left corner of the grid. You are also given a 2D array of coordinates rectangles, where rectangles[i] is in the form [startx, starty, endx, endy], representing a rectangle on the grid. Each rectangle is defined as follows:
(startx, starty): The bottom-left corner of the rectangle.(endx, endy): The top-right corner of the rectangle.Note that the rectangles do not overlap. Your task is to determine if it is possible to make either two horizontal or two vertical cuts on the grid such that:
Return true if such cuts can be made; otherwise, return false.
Example 1:
Input: n = 5, rectangles = [[1,0,5,2],[0,2,2,4],[3,2,5,3],[0,4,4,5]]
Output: true
Explanation:
The grid is shown in the diagram. We can make horizontal cuts at y = 2 and y = 4. Hence, output is true.
Example 2:
Input: n = 4, rectangles = [[0,0,1,1],[2,0,3,4],[0,2,2,3],[3,0,4,3]]
Output: true
Explanation:
We can make vertical cuts at x = 2 and x = 3. Hence, output is true.
Example 3:
Input: n = 4, rectangles = [[0,2,2,4],[1,0,3,2],[2,2,3,4],[3,0,4,2],[3,2,4,4]]
Output: false
Explanation:
We cannot make two horizontal or two vertical cuts that satisfy the conditions. Hence, output is false.
Constraints:
3 <= n <= 1093 <= rectangles.length <= 1050 <= rectangles[i][0] < rectangles[i][2] <= n0 <= rectangles[i][1] < rectangles[i][3] <= nProblem summary: You are given an integer n representing the dimensions of an n x n grid, with the origin at the bottom-left corner of the grid. You are also given a 2D array of coordinates rectangles, where rectangles[i] is in the form [startx, starty, endx, endy], representing a rectangle on the grid. Each rectangle is defined as follows: (startx, starty): The bottom-left corner of the rectangle. (endx, endy): The top-right corner of the rectangle. Note that the rectangles do not overlap. Your task is to determine if it is possible to make either two horizontal or two vertical cuts on the grid such that: Each of the three resulting sections formed by the cuts contains at least one rectangle. Every rectangle belongs to exactly one section. Return true if such cuts can be made; otherwise, return false.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array
5 [[1,0,5,2],[0,2,2,4],[3,2,5,3],[0,4,4,5]]
4 [[0,0,1,1],[2,0,3,4],[0,2,2,3],[3,0,4,3]]
4 [[0,2,2,4],[1,0,3,2],[2,2,3,4],[3,0,4,2],[3,2,4,4]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3394: Check if Grid can be Cut into Sections
class Solution {
// Helper class to mimic C++ pair<int, int>
static class Pair {
int value;
int type;
Pair(int value, int type) {
this.value = value;
this.type = type;
}
}
private boolean countLineIntersections(List<Pair> coordinates) {
int lines = 0;
int overlap = 0;
for (Pair coord : coordinates) {
if (coord.type == 0) {
overlap--;
} else {
overlap++;
}
if (overlap == 0) {
lines++;
}
}
return lines >= 3;
}
public boolean checkValidCuts(int n, int[][] rectangles) {
List<Pair> yCoordinates = new ArrayList<>();
List<Pair> xCoordinates = new ArrayList<>();
for (int[] rectangle : rectangles) {
// rectangle = [x1, y1, x2, y2]
yCoordinates.add(new Pair(rectangle[1], 1)); // y1, start
yCoordinates.add(new Pair(rectangle[3], 0)); // y2, end
xCoordinates.add(new Pair(rectangle[0], 1)); // x1, start
xCoordinates.add(new Pair(rectangle[2], 0)); // x2, end
}
Comparator<Pair> comparator = (a, b) -> {
if (a.value != b.value) return Integer.compare(a.value, b.value);
return Integer.compare(a.type, b.type); // End (0) before Start (1)
};
Collections.sort(yCoordinates, comparator);
Collections.sort(xCoordinates, comparator);
return countLineIntersections(yCoordinates) || countLineIntersections(xCoordinates);
}
}
// Accepted solution for LeetCode #3394: Check if Grid can be Cut into Sections
type Pair struct {
val int
typ int // 1 = start, 0 = end
}
func countLineIntersections(coords []Pair) bool {
lines := 0
overlap := 0
for _, p := range coords {
if p.typ == 0 {
overlap--
} else {
overlap++
}
if overlap == 0 {
lines++
}
}
return lines >= 3
}
func checkValidCuts(n int, rectangles [][]int) bool {
var xCoords []Pair
var yCoords []Pair
for _, rect := range rectangles {
x1, y1, x2, y2 := rect[0], rect[1], rect[2], rect[3]
yCoords = append(yCoords, Pair{y1, 1}) // start
yCoords = append(yCoords, Pair{y2, 0}) // end
xCoords = append(xCoords, Pair{x1, 1})
xCoords = append(xCoords, Pair{x2, 0})
}
sort.Slice(yCoords, func(i, j int) bool {
if yCoords[i].val == yCoords[j].val {
return yCoords[i].typ < yCoords[j].typ // end before start
}
return yCoords[i].val < yCoords[j].val
})
sort.Slice(xCoords, func(i, j int) bool {
if xCoords[i].val == xCoords[j].val {
return xCoords[i].typ < xCoords[j].typ
}
return xCoords[i].val < xCoords[j].val
})
return countLineIntersections(yCoords) || countLineIntersections(xCoords)
}
# Accepted solution for LeetCode #3394: Check if Grid can be Cut into Sections
class Solution:
def countLineIntersections(self, coordinates: List[tuple[int, int]]) -> bool:
lines = 0
overlap = 0
for value, marker in coordinates:
if marker == 0:
overlap -= 1
else:
overlap += 1
if overlap == 0:
lines += 1
return lines >= 3
def checkValidCuts(self, n: int, rectangles: List[List[int]]) -> bool:
y_coordinates = []
x_coordinates = []
for rect in rectangles:
x1, y1, x2, y2 = rect
y_coordinates.append((y1, 1)) # start
y_coordinates.append((y2, 0)) # end
x_coordinates.append((x1, 1)) # start
x_coordinates.append((x2, 0)) # end
# Sort by coordinate value, and for tie, put end (0) before start (1)
y_coordinates.sort(key=lambda x: (x[0], x[1]))
x_coordinates.sort(key=lambda x: (x[0], x[1]))
return self.countLineIntersections(
y_coordinates
) or self.countLineIntersections(x_coordinates)
// Accepted solution for LeetCode #3394: Check if Grid can be Cut into Sections
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #3394: Check if Grid can be Cut into Sections
// class Solution {
// // Helper class to mimic C++ pair<int, int>
// static class Pair {
// int value;
// int type;
//
// Pair(int value, int type) {
// this.value = value;
// this.type = type;
// }
// }
//
// private boolean countLineIntersections(List<Pair> coordinates) {
// int lines = 0;
// int overlap = 0;
//
// for (Pair coord : coordinates) {
// if (coord.type == 0) {
// overlap--;
// } else {
// overlap++;
// }
//
// if (overlap == 0) {
// lines++;
// }
// }
//
// return lines >= 3;
// }
//
// public boolean checkValidCuts(int n, int[][] rectangles) {
// List<Pair> yCoordinates = new ArrayList<>();
// List<Pair> xCoordinates = new ArrayList<>();
//
// for (int[] rectangle : rectangles) {
// // rectangle = [x1, y1, x2, y2]
// yCoordinates.add(new Pair(rectangle[1], 1)); // y1, start
// yCoordinates.add(new Pair(rectangle[3], 0)); // y2, end
//
// xCoordinates.add(new Pair(rectangle[0], 1)); // x1, start
// xCoordinates.add(new Pair(rectangle[2], 0)); // x2, end
// }
//
// Comparator<Pair> comparator = (a, b) -> {
// if (a.value != b.value) return Integer.compare(a.value, b.value);
// return Integer.compare(a.type, b.type); // End (0) before Start (1)
// };
//
// Collections.sort(yCoordinates, comparator);
// Collections.sort(xCoordinates, comparator);
//
// return countLineIntersections(yCoordinates) || countLineIntersections(xCoordinates);
// }
// }
// Accepted solution for LeetCode #3394: Check if Grid can be Cut into Sections
function checkValidCuts(n: number, rectangles: number[][]): boolean {
const check = (arr: number[][], getVals: (x: number[]) => number[]) => {
let [c, longest] = [3, 0];
for (const x of arr) {
const [start, end] = getVals(x);
if (start < longest) {
longest = Math.max(longest, end);
} else {
longest = end;
if (--c === 0) return true;
}
}
return false;
};
const sortByX = ([a]: number[], [b]: number[]) => a - b;
const sortByY = ([, a]: number[], [, b]: number[]) => a - b;
const getX = ([x1, , x2]: number[]) => [x1, x2];
const getY = ([, y1, , y2]: number[]) => [y1, y2];
return check(rectangles.toSorted(sortByX), getX) || check(rectangles.toSorted(sortByY), getY);
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.