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.
An n x n grid is composed of 1 x 1 squares where each 1 x 1 square consists of a '/', '\', or blank space ' '. These characters divide the square into contiguous regions.
Given the grid grid represented as a string array, return the number of regions.
Note that backslash characters are escaped, so a '\' is represented as '\\'.
Example 1:
Input: grid = [" /","/ "] Output: 2
Example 2:
Input: grid = [" /"," "] Output: 1
Example 3:
Input: grid = ["/\\","\\/"] Output: 5 Explanation: Recall that because \ characters are escaped, "\\/" refers to \/, and "/\\" refers to /\.
Constraints:
n == grid.length == grid[i].length1 <= n <= 30grid[i][j] is either '/', '\', or ' '.Problem summary: An n x n grid is composed of 1 x 1 squares where each 1 x 1 square consists of a '/', '\', or blank space ' '. These characters divide the square into contiguous regions. Given the grid grid represented as a string array, return the number of regions. Note that backslash characters are escaped, so a '\' is represented as '\\'.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Union-Find
[" /","/ "]
[" /"," "]
["/\\","\\/"]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #959: Regions Cut By Slashes
class Solution {
private int[] p;
private int size;
public int regionsBySlashes(String[] grid) {
int n = grid.length;
size = n * n * 4;
p = new int[size];
for (int i = 0; i < p.length; ++i) {
p[i] = i;
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
int k = i * n + j;
if (i < n - 1) {
union(4 * k + 2, (k + n) * 4);
}
if (j < n - 1) {
union(4 * k + 1, (k + 1) * 4 + 3);
}
char v = grid[i].charAt(j);
if (v == '/') {
union(4 * k, 4 * k + 3);
union(4 * k + 1, 4 * k + 2);
} else if (v == '\\') {
union(4 * k, 4 * k + 1);
union(4 * k + 2, 4 * k + 3);
} else {
union(4 * k, 4 * k + 1);
union(4 * k + 1, 4 * k + 2);
union(4 * k + 2, 4 * k + 3);
}
}
}
return size;
}
private int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
private void union(int a, int b) {
int pa = find(a);
int pb = find(b);
if (pa == pb) {
return;
}
p[pa] = pb;
--size;
}
}
// Accepted solution for LeetCode #959: Regions Cut By Slashes
func regionsBySlashes(grid []string) int {
n := len(grid)
size := n * n * 4
p := make([]int, size)
for i := range p {
p[i] = i
}
var find func(x int) int
find = func(x int) int {
if p[x] != x {
p[x] = find(p[x])
}
return p[x]
}
union := func(a, b int) {
pa, pb := find(a), find(b)
if pa == pb {
return
}
p[pa] = pb
size--
}
for i, row := range grid {
for j, v := range row {
k := i*n + j
if i < n-1 {
union(4*k+2, (k+n)*4)
}
if j < n-1 {
union(4*k+1, (k+1)*4+3)
}
if v == '/' {
union(4*k, 4*k+3)
union(4*k+1, 4*k+2)
} else if v == '\\' {
union(4*k, 4*k+1)
union(4*k+2, 4*k+3)
} else {
union(4*k, 4*k+1)
union(4*k+1, 4*k+2)
union(4*k+2, 4*k+3)
}
}
}
return size
}
# Accepted solution for LeetCode #959: Regions Cut By Slashes
class Solution:
def regionsBySlashes(self, grid: List[str]) -> int:
def find(x):
if p[x] != x:
p[x] = find(p[x])
return p[x]
def union(a, b):
pa, pb = find(a), find(b)
if pa != pb:
p[pa] = pb
nonlocal size
size -= 1
n = len(grid)
size = n * n * 4
p = list(range(size))
for i, row in enumerate(grid):
for j, v in enumerate(row):
k = i * n + j
if i < n - 1:
union(4 * k + 2, (k + n) * 4)
if j < n - 1:
union(4 * k + 1, (k + 1) * 4 + 3)
if v == '/':
union(4 * k, 4 * k + 3)
union(4 * k + 1, 4 * k + 2)
elif v == '\\':
union(4 * k, 4 * k + 1)
union(4 * k + 2, 4 * k + 3)
else:
union(4 * k, 4 * k + 1)
union(4 * k + 1, 4 * k + 2)
union(4 * k + 2, 4 * k + 3)
return size
// Accepted solution for LeetCode #959: Regions Cut By Slashes
struct Solution;
struct UnionFind {
parent: Vec<usize>,
n: usize,
}
impl UnionFind {
fn new(n: usize) -> Self {
let parent = (0..n).collect();
UnionFind { parent, n }
}
fn find(&mut self, i: usize) -> usize {
let j = self.parent[i];
if i == j {
i
} else {
self.parent[i] = self.find(j);
self.parent[i]
}
}
fn union(&mut self, mut i: usize, mut j: usize) {
i = self.find(i);
j = self.find(j);
if i != j {
self.parent[i] = j;
self.n -= 1;
}
}
}
impl Solution {
fn regions_by_slashes(grid: Vec<String>) -> i32 {
let a: Vec<Vec<char>> = grid.iter().map(|s| s.chars().collect()).collect();
let n = grid.len();
let m = a[0].len();
let mut uf = UnionFind::new(n * m * 4);
for i in 0..n {
for j in 0..m {
let k0 = Self::id(0, i, j, n, m);
let k1 = Self::id(1, i, j, n, m);
let k2 = Self::id(2, i, j, n, m);
let k3 = Self::id(3, i, j, n, m);
match a[i][j] {
' ' => {
uf.union(k0, k1);
uf.union(k1, k2);
uf.union(k2, k3);
uf.union(k3, k0);
}
'/' => {
uf.union(k0, k1);
uf.union(k2, k3);
}
'\\' => {
uf.union(k1, k2);
uf.union(k3, k0);
}
_ => {}
}
if i > 0 {
uf.union(k1, Self::id(3, i - 1, j, n, m));
}
if j > 0 {
uf.union(k0, Self::id(2, i, j - 1, n, m));
}
}
}
uf.n as i32
}
fn id(k: usize, i: usize, j: usize, n: usize, m: usize) -> usize {
k * n * m + i * m + j
}
}
#[test]
fn test() {
let grid = vec_string![" /", "/ "];
let res = 2;
assert_eq!(Solution::regions_by_slashes(grid), res);
let grid = vec_string![" /", " "];
let res = 1;
assert_eq!(Solution::regions_by_slashes(grid), res);
let grid = vec_string!["\\/", "/\\"];
let res = 4;
assert_eq!(Solution::regions_by_slashes(grid), res);
}
// Accepted solution for LeetCode #959: Regions Cut By Slashes
function regionsBySlashes(grid: string[]): number {
const find = (x: number) => {
if (p[x] !== x) {
p[x] = find(p[x]);
}
return p[x];
};
const union = (a: number, b: number) => {
const pa = find(a);
const pb = find(b);
if (pa !== pb) {
p[pa] = pb;
size--;
}
};
const n = grid.length;
let size = n * n * 4;
const p = Array.from({ length: size }, (_, i) => i);
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
const k = i * n + j;
if (i < n - 1) {
union(4 * k + 2, (k + n) * 4);
}
if (j < n - 1) {
union(4 * k + 1, (k + 1) * 4 + 3);
}
if (grid[i][j] === '/') {
union(4 * k, 4 * k + 3);
union(4 * k + 1, 4 * k + 2);
} else if (grid[i][j] === '\\') {
union(4 * k, 4 * k + 1);
union(4 * k + 2, 4 * k + 3);
} else {
union(4 * k, 4 * k + 1);
union(4 * k + 1, 4 * k + 2);
union(4 * k + 2, 4 * k + 3);
}
}
}
return size;
}
Use this to step through a reusable interview workflow for this problem.
Track components with a list or adjacency matrix. Each union operation may need to update all n elements’ component labels, giving O(n) per union. For n union operations total: O(n²). Find is O(1) with direct lookup, but union dominates.
With path compression and union by rank, each find/union operation takes O(α(n)) amortized time, where α is the inverse Ackermann function — effectively constant. Space is O(n) for the parent and rank arrays. For m operations on n elements: O(m × α(n)) total.
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.