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 a positive integer n, representing an n x n city. You are also given a 2D grid buildings, where buildings[i] = [x, y] denotes a unique building located at coordinates [x, y].
A building is covered if there is at least one building in all four directions: left, right, above, and below.
Return the number of covered buildings.
Example 1:
Input: n = 3, buildings = [[1,2],[2,2],[3,2],[2,1],[2,3]]
Output: 1
Explanation:
[2,2] is covered as it has at least one building:
[1,2])[3,2])[2,1])[2,3])Example 2:
Input: n = 3, buildings = [[1,1],[1,2],[2,1],[2,2]]
Output: 0
Explanation:
Example 3:
Input: n = 5, buildings = [[1,3],[3,2],[3,3],[3,5],[5,3]]
Output: 1
Explanation:
[3,3] is covered as it has at least one building:
[1,3])[5,3])[3,2])[3,5])Constraints:
2 <= n <= 1051 <= buildings.length <= 105 buildings[i] = [x, y]1 <= x, y <= nbuildings are unique.Problem summary: You are given a positive integer n, representing an n x n city. You are also given a 2D grid buildings, where buildings[i] = [x, y] denotes a unique building located at coordinates [x, y]. A building is covered if there is at least one building in all four directions: left, right, above, and below. Return the number of covered buildings.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
3 [[1,2],[2,2],[3,2],[2,1],[2,3]]
3 [[1,1],[1,2],[2,1],[2,2]]
5 [[1,3],[3,2],[3,3],[3,5],[5,3]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3531: Count Covered Buildings
class Solution {
public int countCoveredBuildings(int n, int[][] buildings) {
Map<Integer, List<Integer>> g1 = new HashMap<>();
Map<Integer, List<Integer>> g2 = new HashMap<>();
for (int[] building : buildings) {
int x = building[0], y = building[1];
g1.computeIfAbsent(x, k -> new ArrayList<>()).add(y);
g2.computeIfAbsent(y, k -> new ArrayList<>()).add(x);
}
for (var e : g1.entrySet()) {
Collections.sort(e.getValue());
}
for (var e : g2.entrySet()) {
Collections.sort(e.getValue());
}
int ans = 0;
for (int[] building : buildings) {
int x = building[0], y = building[1];
List<Integer> l1 = g1.get(x);
List<Integer> l2 = g2.get(y);
if (l2.get(0) < x && x < l2.get(l2.size() - 1) && l1.get(0) < y
&& y < l1.get(l1.size() - 1)) {
ans++;
}
}
return ans;
}
}
// Accepted solution for LeetCode #3531: Count Covered Buildings
func countCoveredBuildings(n int, buildings [][]int) (ans int) {
g1 := make(map[int][]int)
g2 := make(map[int][]int)
for _, building := range buildings {
x, y := building[0], building[1]
g1[x] = append(g1[x], y)
g2[y] = append(g2[y], x)
}
for _, list := range g1 {
sort.Ints(list)
}
for _, list := range g2 {
sort.Ints(list)
}
for _, building := range buildings {
x, y := building[0], building[1]
l1 := g1[x]
l2 := g2[y]
if l2[0] < x && x < l2[len(l2)-1] && l1[0] < y && y < l1[len(l1)-1] {
ans++
}
}
return
}
# Accepted solution for LeetCode #3531: Count Covered Buildings
class Solution:
def countCoveredBuildings(self, n: int, buildings: List[List[int]]) -> int:
g1 = defaultdict(list)
g2 = defaultdict(list)
for x, y in buildings:
g1[x].append(y)
g2[y].append(x)
for x in g1:
g1[x].sort()
for y in g2:
g2[y].sort()
ans = 0
for x, y in buildings:
l1 = g1[x]
l2 = g2[y]
if l2[0] < x < l2[-1] and l1[0] < y < l1[-1]:
ans += 1
return ans
// Accepted solution for LeetCode #3531: Count Covered Buildings
use std::collections::HashMap;
impl Solution {
pub fn count_covered_buildings(_n: i32, buildings: Vec<Vec<i32>>) -> i32 {
let mut g1: HashMap<i32, Vec<i32>> = HashMap::new();
let mut g2: HashMap<i32, Vec<i32>> = HashMap::new();
for b in &buildings {
let x = b[0];
let y = b[1];
g1.entry(x).or_insert(Vec::new()).push(y);
g2.entry(y).or_insert(Vec::new()).push(x);
}
for v in g1.values_mut() {
v.sort();
}
for v in g2.values_mut() {
v.sort();
}
let mut ans: i32 = 0;
for b in &buildings {
let x = b[0];
let y = b[1];
let l1 = g1.get(&x).unwrap();
let l2 = g2.get(&y).unwrap();
if l2[0] < x && x < l2[l2.len() - 1] && l1[0] < y && y < l1[l1.len() - 1] {
ans += 1;
}
}
ans
}
}
// Accepted solution for LeetCode #3531: Count Covered Buildings
function countCoveredBuildings(n: number, buildings: number[][]): number {
const g1: Map<number, number[]> = new Map();
const g2: Map<number, number[]> = new Map();
for (const [x, y] of buildings) {
if (!g1.has(x)) g1.set(x, []);
g1.get(x)?.push(y);
if (!g2.has(y)) g2.set(y, []);
g2.get(y)?.push(x);
}
for (const list of g1.values()) {
list.sort((a, b) => a - b);
}
for (const list of g2.values()) {
list.sort((a, b) => a - b);
}
let ans = 0;
for (const [x, y] of buildings) {
const l1 = g1.get(x)!;
const l2 = g2.get(y)!;
if (l2[0] < x && x < l2[l2.length - 1] && l1[0] < y && y < l1[l1.length - 1]) {
ans++;
}
}
return ans;
}
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.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.