LeetCode #2352 Medium

Equal Row and Column Pairs

Equal Row and Column Pairs is LeetCode 2352 (Medium). Given an n × n grid of integers, count the pairs (r, c) where row r and column c hold the same values in the same order: grid[r][0], grid[r][1], … equals grid[0][c], grid[1][c], ….

  • Any row can pair with any column, so r and c need not be equal.
  • n is at most 200, small enough that even an O(n³) check passes.
Constraints
  • n == grid.length == grid[i].length
  • 1 <= n <= 200
  • 1 <= grid[i][j] <= 10⁵
arrayhash-tablematrixsimulation
Open on LeetCode ↗
02

Intuition

A row and a column are equal only if they are the same sequence from start to finish. So instead of comparing every row with every column, turn each row into one key: the whole sequence, in order.

  • Count the rows: a hash map from each row's key to how many rows have it.
  • Look up the columns: build each column's key the same way and add the count stored for it.

A column whose sequence appears in three rows forms three pairs, and three is exactly the count in the map. Building and hashing a key costs O(n), and there are 2n keys, so the work drops from O(n³) to O(n²).

How to spot this pattern

When the question is how many pairs of things are identical, and each thing is a whole sequence, hash the sequence and count. It is the same move as grouping anagrams by a sorted key, or finding duplicate rows in a table.

03

Approach

Try it first

Before reading on: in [[3, 1, 2, 2], [1, 4, 4, 5], [2, 4, 2, 2], [2, 4, 2, 2]], find every row that equals some column. How many pairs does column 2 make, and why? Then think of one value that could stand for a whole row so a column can be matched in a single lookup. Aim for O(n²).

1

Count every row by its sequence

Build Counter(tuple(row) for row in grid). A tuple keeps the values in order and can be used as a dictionary key; a list cannot, because a list could change after it is stored.

2

Build each column the same way

For column c, collect grid[0][c], grid[1][c], …, grid[n-1][c] into a tuple. It now has the same shape as a row key, so equal sequences give equal keys.

3

Add the count for each column

Add row_count[column] to the running total, then return the total after the last column. A Counter returns 0 for a key it has never seen, so a column that matches no row adds nothing.

04

Equal Row and Column Pairs solution in Python | C++ | Java

▶1from collections import Counter
▶2 
▶3class Solution:
▶4 def equalPairs(self, grid: List[List[int]]) -> int:
▶5 n = len(grid)
▶6 row_count = Counter(tuple(row) for row in grid)
▶7 pairs = 0
▶8 for c in range(n):
▶9 column = tuple(grid[r][c] for r in range(n))
▶10 pairs += row_count[column]
▶11 return pairs
col 0col 1col 2032111762277row counts3, 2, 11pairs0row 0 is a new sequence → count 1
row 03, 2, 1
count1
Row 0 becomes one key: the whole sequence 3, 2, 1, in order. The key is a tuple, so it can be looked up later in one step instead of being compared value by value.
col 0col 1col 2032111762277row counts3, 2, 111, 7, 61pairs0row 1 is a new sequence → count 1
row 11, 7, 6
count1
Row 1 becomes one key: the whole sequence 1, 7, 6, in order. The key is a tuple, so it can be looked up later in one step instead of being compared value by value.
col 0col 1col 2032111762277row counts3, 2, 111, 7, 612, 7, 71pairs0row 2 is a new sequence → count 1
row 22, 7, 7
count1
Row 2 becomes one key: the whole sequence 2, 7, 7, in order. The key is a tuple, so it can be looked up later in one step instead of being compared value by value.
col 0col 1col 2032111762277row counts3, 2, 111, 7, 612, 7, 71pairs0column 0 matches no row → +0
column 03, 1, 2
rows with it0
pairs0
Read column 0 top to bottom: 3, 1, 2. No row has this sequence in this order, so the lookup returns 0 and no pair is added.
col 0col 1col 2032111762277row counts3, 2, 111, 7, 612, 7, 71pairs1column 1 matches 1 row → +1
column 12, 7, 7
rows with it1
pairs1
Read column 1 top to bottom: 2, 7, 7. That exact sequence is in the table with count 1, so it forms 1 pair, one with each matching row. Pairs so far: 1.
col 0col 1col 2032111762277row counts3, 2, 111, 7, 612, 7, 71pairs1column 2 matches no row → +0
column 21, 6, 7
rows with it0
pairs1
Read column 2 top to bottom: 1, 6, 7. No row has this sequence in this order, so the lookup returns 0 and no pair is added.
col 0col 1col 2032111762277row counts3, 2, 111, 7, 612, 7, 71pairs1answer: 1
answer1row and column pairs
Each row was stored once and each column was looked up once, so every cell was read twice. The answer is 1.
05

Compare every row with every column

For every row r and column c, walk k from 0 while grid[r][k] == grid[k][c]. If k reaches n, the whole row matched the whole column and the pair counts. At n = 200 that is at most 8 million comparisons, and most pairs stop after the first value.

▶1class Solution:
▶2 def equalPairs(self, grid: List[List[int]]) -> int:
▶3 n = len(grid)
▶4 pairs = 0
▶5 for r in range(n):
▶6 for c in range(n):
▶7 k = 0
▶8 while k < n and grid[r][k] == grid[k][c]:
▶9 k += 1
▶10 if k == n:
▶11 pairs += 1
▶12 return pairs
06

Common pitfalls

Reading a row when you meant a column

✗ Wrong
column = tuple(grid[c][r] for r in range(n))
✓ Right
column = tuple(grid[r][c] for r in range(n))

grid[c][r] with r moving walks along row c, so every "column" is really a row and finds itself in the map. On [[3, 2, 1], [1, 7, 6], [2, 7, 7]] that returns 3, but only row 2 and column 1 match, so the answer is 1.

Gluing values together without a separator

✗ Wrong
key = "".join(map(str, row))
✓ Right
key = tuple(row)  # or ",".join(map(str, row))

Numbers of different lengths run into each other. In [[11, 1], [2, 11]], row 0 becomes "111" and column 1, which is 1, 11, also becomes "111". The code returns 1, but no row equals a column, so the answer is 0.

Keeping a set of rows instead of a count

✗ Wrong
rows = set(tuple(r) for r in grid)
pairs += column in rows
✓ Right
row_count = Counter(tuple(r) for r in grid)
pairs += row_count[column]

A set forgets how many rows had each sequence. In [[2, 2], [2, 2]] both rows equal both columns, so there are 4 pairs, but the set holds one key and the code returns 2.

07

Complexity

Time
O(n²)
Space
O(n²)
Building the row keys reads every cell once and building the column keys reads every cell again. Hashing a key of length n costs O(n), so the n lookups add O(n²) more. The map holds up to n keys of n values each.
08

Equal Row and Column Pairs FAQ

Why does the C++ code use map instead of unordered_map?

C++ has no built-in hash for vector<int>, so unordered_map<vector<int>, int> does not compile without a custom hasher. map compares vectors instead, which costs O(n log n) per lookup and O(n² log n) in total, fine for n = 200. For a true O(n²), key on a string with a separator between values.